【Java4】实例初始化,类初始化,/接口,多态,final/static,权限修饰符/native
文章目錄
- 1.實例初始化過程:有幾個構造器,就會有幾個實例初始化方法
- 2.實例初始化和類初始化結合:先類(靜態)后實
- 3.接口:只有abstract可省
- 3.1 鳥類案例:Flyable相當于父類的一個補丁,因為有的鳥會飛,有的鳥不會飛
- 3.2 繼承(extends)和實現(implements):extends B,C錯
- 4.多態:和屬性無關,只說方法
- 4.1 多態弊端:用instanceof 避免
- 4.2 多態應用:USB相當于animal抽象類改為接口,里面connect是抽象方法
- 5.final:final只有get方法
- 6.static:修飾的成變不進堆
- 7.四大權限修飾符:記住中間兩個本包,ppdp
- 8.native:調用C/C++
1.實例初始化過程:有幾個構造器,就會有幾個實例初始化方法
package com.atguigu.test01.block; /** 1、類的成員:* (1)屬性:成員變量* (2)方法:成員方法* (3)構造器* (4)代碼塊分為如下:非靜態代碼塊, 靜態代碼塊(后面講,和static一起說)* * 2、非靜態代碼塊* (1)聲明的格式:* 【修飾符】 class 類名{* {* 非靜態代碼塊;* }* }* (2)非靜態代碼塊中的代碼什么時候執行? 在“每次”創建對象的時候執行,比構造器早執行。* (3)實例初始化過程:創建對象時,為對象進行初始化的操作,如下【1】和【2】按代碼先后,反正【3】最后。* 【1】為成員變量顯式賦值 【2】執行非靜態代碼塊 【3】執行構造器* * Java編譯器會把這三個部分的代碼,合成一個叫做<init>(【形參列表】)(在.class中)實例初始化方法* 即編譯后的.class字節碼信息中,是沒有構造器這個概念。 */ public class TestBlock {public static void main(String[] args) { Demo d1 = new Demo();//調用無參構造,本質上是調用<init>()實例初始化方法Demo d2 = new Demo("atguigu");//調用有參構造,本質上是調用<init>(形參列表)實例初始化方法} }class Demo{{System.out.println("非靜態代碼塊1");} private String str = assign();//調用方法,來為str進行顯式賦值public Demo(){System.out.println("無參構造");}public Demo(String str){this.str = str;System.out.println("有參構造");}{System.out.println("非靜態代碼塊2");}public String assign(){System.out.println("assign方法");return "hello";} }如下的線上面是d1實例初始化過程,都是構造排最后。
2.實例初始化和類初始化結合:先類(靜態)后實
package com.atguigu.test04;public class TestInit {public static void main(String[] args) {Demo d = new Demo();//2631745} } class Demo{{System.out.println("(1)Demo的非靜態代碼塊1");}static{System.out.println("(2)Demo的靜態代碼塊1");}private static String info = assign();private String message = getMessage();static{System.out.println("(3)Demo的靜態代碼塊2");}{System.out.println("(4)Demo的非靜態代碼塊2");}public Demo(){System.out.println("(5)無參構造");}public static String assign(){System.out.println("(6)assign()方法");return "hello";}public String getMessage(){System.out.println("(7)getMessage()方法");return "msg";} } package com.atguigu.test04; /** (1)先完成父類的類初始化* (2)再完成子類的類初始化* (3)父類的實例初始化方法* (4)子類的實例初始化方法*/ public class TestInit2 {public static void main(String[] args) {DemoZi zi1 = new DemoZi(); //2,6,3/,9,13,10/,1,14,4,5/,8,14,11,12System.out.println("-------------------");DemoZi zi2 = new DemoZi();} } class DemoFu{{System.out.println("(1)Demo的非靜態代碼塊1");}static{System.out.println("(2)Demo的靜態代碼塊1");}private static String info = assign();private String message = getMessage(); //子類重寫了static{System.out.println("(3)Demo的靜態代碼塊2");}{System.out.println("(4)Demo的非靜態代碼塊2");}public DemoFu(){System.out.println("(5)無參構造");}public static String assign(){System.out.println("(6)assign()方法");return "hello";}public String getMessage(){System.out.println("(7)getMessage()方法");return "msg";} } class DemoZi extends DemoFu{{System.out.println("(8)");}static{System.out.println("(9)");}private static String info = assign();private String message = getMessage();static{System.out.println("(10)");}{System.out.println("(11)");}public DemoZi(){System.out.println("(12)");}public static String assign(){System.out.println("(13)");return "hello";}public String getMessage(){System.out.println("(14)getMessage()方法");return "msg";} }3.接口:只有abstract可省
抽(abstract可省)/默(default不可省)。靜(static不可省,方片,類名/接口名.)/常。
類中只有final修飾要初始化,其他不需要。
3.1 鳥類案例:Flyable相當于父類的一個補丁,因為有的鳥會飛,有的鳥不會飛
package com.itheima05.bird;public class BirdDemo {public static void main(String[] args) {Sparrow sparrow = new Sparrow();sparrow.name = "杰克";sparrow.eat(); //杰克正在吃東西sparrow.fly(); //杰克正在撲騰Qq qq = new Qq();qq.name = "企鵝";qq.eat(); //企鵝正在吃東西} } class Bird{String name;int age;//alt+insert快捷鍵構造函數,但必須鼠標停在類中public Bird(){}public Bird(String name, int age) {this.name = name;this.age = age;}public void eat(){System.out.println(name + "正在吃東西");} }//11111111111111111111111111111111111111111111111111111111111111111111111 interface Flyable{void fly(); //抽象方法 } class Sparrow extends Bird implements Flyable{ //子類默認調用父類的空參構造@Overridepublic void fly() {System.out.println(name + "正在撲騰");} } class Qq extends Bird{ }如下和上面無關。
public class TestInterfaceDefineAndUse {public static void main(String[] args) { // Flyable f = new Flyable();//接口不能直接創建對象的Flyable[] sky = new Flyable[3]; //存放接口的數組//數組的元素類型Flyable類型,是接口類型sky[0] = new Bird();//多態引用sky[1] = new Plane();sky[2] = new Kite(); for (int i = 0; i < sky.length; i++) {//數組的元素類型Flyable類型,是接口類型sky[i].fly();}} } interface Flyable{ // public static final long MAX_SPEED = 7900000;long MAX_SPEED = 7900000; // public abstract void fly();void fly(); } interface Jumpable{void jump(); } class Animal{ }//1111111111111111111111111111111111111111111111111111111111111111111 class Bird extends Animal implements Flyable,Jumpable {//重寫接口的抽象方法,實現接口的抽象方法@Overridepublic void fly() {System.out.println("小鳥振翅高飛");}@Overridepublic void jump() {System.out.println("雙腳跳");} }class Plane implements Flyable{@Overridepublic void fly() {System.out.println("靠發動機帶動飛行");} } class Kite implements Flyable{@Overridepublic void fly() {System.out.println("靠人放");} }//1111111111111111111111111111111111111111111111111111111111111111 interface A{void a(); } interface B{void b(); } interface C extends A,B{void c(); } class Impl implements C{ //必須重寫3個方法@Overridepublic void a() {}@Overridepublic void b() {}@Overridepublic void c() {} }
因為接口必須重寫抽象方法,吃草吃肉和J無關。
3.2 繼承(extends)和實現(implements):extends B,C錯
package com.itheima06.tedian; /* * 1. 類繼承類: 只能單繼承,不能多繼承 class A extends B { } * 2. 類實現接口: 可以多實現,沒有接口與類之間關系 class A implements B,C...{ } * 3. 接口繼承接口: 可以多繼承 interface A extends B,C...{ } */ public class Demo03 {public static void main(String[] args) {} } interface M{void eat(); } interface L{void run(); } interface N extends M,L{ }class O implements N{ //1@Override public void eat() {}@Overridepublic void run() {} }class P implements M,L{ //2同1@Overridepublic void eat() {}@Overridepublic void run() {} } package com.itheima06.tedian; /** 1. 一個類S 繼承類Q, 又實現接口R (而Q和R又有相同的方法)* 符合就近原則: 繼承類Q中的方法 * 2. (而Q和R又有相同的方法 : Q中方法不抽象 R方法抽象)* 那么子類不用重寫R中抽象方法。原理: 用Q中繼承過來的方法來 代替 抽象方法重寫*/ public class Demo04 {public static void main(String[] args) { S s = new S();s.eat(); //吃草} } abstract class Q{public void eat(){System.out.println("吃草");}public abstract void eat2();public void eat3(){ //不抽象,S類中不用重寫} } interface R{default void eat(){System.out.println("吃肉");}void eat2();void eat3(); } class S extends Q implements R{@Overridepublic void eat2() { //必須重寫抽象方法} } /*1. 任何一個類(除Object之外), 如果沒有顯示聲明繼承哪個,那么直接繼承Object2. 用類中繼承來的同名方法 代替 接口中的抽象方法重寫 */ interface T{boolean equals(Object obj); } class U implements T{ //class U extends Object implements T //Object有equals方法 }4.多態:和屬性無關,只說方法
package com.itheima07.duotai; /* * java精髓: 接口和多態。多態:提高代碼擴展性(當需求改變的時候,代碼改的越少,擴展性越強) * 1. 含義: 一種行為卻展示出多種形態 * 2. 表述: 父類/父接口 引用 指向子類對象。 父類/父接口 引用調用方法,執行的是子類重寫的方法 * 3. 多態三要素,必要條件 * 1. 繼承 (類繼承,接口) * 2. 重寫 (方法重寫) * 3. 向上轉型 (父類引用指向子類對象) * * 向上轉型(默認成立的) * 1. 前提 : 基于繼承關系 * 2. 格式:父類類型 變量/引用 = new 子類類型(); * 3. 含義:子類對象 實際上 都可以說是 父類中一種實例即看到狗就說它是種動物 * * 為什么一定需要方法重寫? 編譯看左邊,運行看右邊 * 1. 運行的時候,子類對象會運行子類重寫的方法,無論左邊類型是父類/子類(Animal/Dog) * 2. 問題: 父類中定義的方法 沒有用,那為什么一定要寫? 是為了通過編譯 * 1. 編譯看左邊 * java代碼 -> .class文件 -> runtime * 編譯 運行 * (編譯器 : 不知道運行階段的事 即 右邊的事不關心) * 2. 運行看右邊:右邊的內容是在運行階段賦值給左邊 */ public class DuotaiDemo {public static void main(String[] args) { // Dog dog = new Dog(); //這是方法重寫不是多態 // dog.eat();//向上轉型 : 前提繼承。如下a是內存地址/變量/引用 即 父類引用指向子類對象Animal a = new Dog(); //多態的表現出來的特征:1.編譯類型與運行時類型不一致,2.方法重寫a.eat();// 一種行為eat,多種形態(什么形態.具體要取決是什么對象)。//打印出:狗在吃骨頭} }//11111111111111111111111111111111111111111111111111111111111111111 abstract class Animal{public void eat(){System.out.println("動物在吃飯");} } class Dog extends Animal{public void eat() {System.out.println("狗在吃骨頭");} } class Cat extends Animal{public void eat() {System.out.println("貓在吃魚");} }
如下通過編譯了,運行報錯(右邊true運行時才賦值給左邊)。
4.1 多態弊端:用instanceof 避免
如下是多態的好處。
如下不看注釋掉的,只需給method(new Dog())傳入實參,更簡便。
如上會出現問題:貓, 狗,狼 吃各自的東西。但如果是貓, 貓還會加餐吃 貓糧即add方法(如鉆石會員加個特效)。
如下是強制向下轉型弊端:method(new Dog())。
4.2 多態應用:USB相當于animal抽象類改為接口,里面connect是抽象方法
如下extend()相當于上面method(),USB usb相當于Animal a,usb.connect()相當于a.eat()。
接口是規范/標準,多態是拓展性。
5.final:final只有get方法
package com.itheima00.question; public class Demo01 {public static void main(String[] args) {// 繼承關系分為如下兩種:FuClass fc = new Zi(); //類繼承 FuIn fi = new Zi(); //接口實現 // 如上向上轉型,如下向下轉型 // 父類類型變量 instanceof 子類類型:用來判斷是不是繼承的// boolean result = fc instanceof String; //錯誤,因為fc和String沒有繼承關系 boolean result = fi instanceof Zi;//可以true,fc instanceof Zi也為true} } interface FuIn{ } class FuClass{ } class Zi extends FuClass implements FuIn{ } package com.itheima01.finald; /* * final:不可繼承(類)如String類很完美 不可重寫(方法) 不可修改(屬性) * 方法重寫的出現打破了類的封裝性, final修飾方法既保證了封裝,又保證了繼承 */ public class Demo01 {public static void main(String[] args) {C c = new C();c.eat(); //不能重寫但能繼承 //聯合聲明: ~~} } class B {public final void eat(){ //final 修飾方法可繼承,不是類。System.out.println("聯合聲明: ~~");} } class C extends B{ //C是B的發言人 }
如下i有默認初始值0,所以若final int j = 0,final寫了沒意義,主因D類使用時無法給j賦值。
解決如上問題還有如下構造器方法,但是需要刪除有漏洞的有參構造器。
如下無漏洞的有參構造器。
6.static:修飾的成變不進堆
package com.itheima02.staticd; /* * static 修飾:1.屬性,2.方法,3.代碼塊 * static修飾屬性 * 1. 可以用類名/接口名 直接訪問 !!! * 問題: 為什么非靜態屬性必須對象調用? 而靜態屬性可以類名調用? * 因為static是屬于類的, 隨著類的加載而加載, 優先于對象 * 1. 非靜態屬性在堆里中,屬于對象的 (有幾個對象,就有幾份) * 2. 靜態屬性在方法區(類區)中, 屬于類的 (在內存只有一份,共享一值) * * 2. 靜態屬性 也可以 通過對象名來調用(不推薦) : 每個對象實際上都是類的實例 * 3. 靜態屬性 被該類所有對象所共享 (只有一個對象進行修改,那么其他對象的該靜態屬性都會隨之修改) * 運用: 非靜態屬性各自對象私有, 靜態屬性大家共有 */ public class StaticDemo01 {public static void main(String[] args) {/* A a = new A();System.out.println(a.i); // 可以,a為對象System.out.println(A.j);*/ //可以,A為類名A a1 = new A();a1.i = 2;A a2 = new A();System.out.println(a2.i);// 1,不是2System.out.println(A.j); //以下這幾個都一樣都為2System.out.println(a1.j);System.out.println(a2.j);System.out.println("--------------------");a1.j = 10;System.out.println(a2.j); //10,j靜態,改了都改a2.j = 20;System.out.println(a1.j); //20System.out.println(A.j); //20System.out.println("--------------------");Student s1 = new Student();Student s2 = new Student();s1.schoolName = "黑馬";System.out.println(s2.schoolName); //黑馬Student.schoolName = "白馬";System.out.println(s1.schoolName); //白馬} } class A{int i = 1; //非靜態屬性static int j = 2; //靜態屬性,不給值也沒事,因為static可以使用默認初始值,不是final } class Student{String name;int age;int money;static String schoolName; } package com.itheima02.staticd; /* * static修飾方法:0. static隨著類的加載而加載, static內容屬于類不會進堆。static修飾的內容加載時會進方法區(靜態區/類區),非static修飾的內容加載時會進方法區(非靜態區/對象區)。 * * 1. static方法 可以通過類名調用 * 問題: 為什么 非靜態方法地址 要記錄到 堆內存? * 原因: 非靜態方法 可以訪問 非靜態屬性 , 不同的對象的非靜態屬性是不一樣的 * 不同的對象 非靜態方法 執行效果也有所不同,所以涉及對象,進堆 * * 2. static屬于類的,跟對象無關 (static優先于對象加載 : 先來調用后到的) * 2.1 static方法不能調用非靜態的屬性和方法(跟對象有關系都不可以) * 2.2 this 和super關鍵字都不行 * 只要該類對象, 調用靜態方法執行效果都一樣!!! */ public class StaticDemo02 {public static void main(String[] args) { B b1 = new B(); b1.name = "張三";B b2 = new B(); //又new了,地址不同b2.name = "李四";b1.method01(); //張三:method01 com.itheima.demo02.B@4554617cb2.method01(); //李四:method01 com.itheima.demo02.B@74a14482b1.method02(); //static method02b2.method02(); //static method02B.method02(); //static method02B b = null; //null指堆是空的,找不到method01()//b.method01(); //NullPointerException 空指針異常 空引用b.method02(); //static method02,對象是空的也沒事,靜態方法不進堆} } class B{String name;public void method01(){System.out.println(name + ":method01");System.out.println(this); //com.itheima.demo02.B@4554617c//System.out.println(this.name); }public static void method02(){//public和static位置無所謂,只要在返回值前就可以System.out.println( "static method02");} }如下method02靜態,this屬于對象,所以報錯。加上name+"static…"會報錯,因為name非靜態,定義改為static String name就可以。
如下沒有創建對象,沒有調用方法,運行依然顯示:靜態代碼塊。
如下因為info是static,所以assign方法也應為static。
如下不確定=非靜態。
7.四大權限修飾符:記住中間兩個本包,ppdp
package com.itheima03.privilege; import com.itheima00.question.Fu; /* * java四大權限修飾符:public > protected > default(不寫) > private * 1. public : 公共的 , 全工程可訪問 * 2. protected : 受保護的 , 【本包 + 跨包子類內部】 * 3. default : 默認, 【本包】 * 4. private: 私有, 除【本類】內部,其他不可訪問 */ public class FourDemo {public static void main(String[] args) {Fu fu = new Fu();Zi zi = new Zi();} } class Zi extends Fu{ public void eat(){System.out.println(id1);System.out.println(id2); //跨包 子類的內部可訪問 //import com.itheima00.question.Fu;} } package com.itheima04.review; /* * 修飾符:static,final,abstract,default * 修飾符矛盾 (編譯報錯): * 1. private 和 abstract 不能共存: abstract方法不重寫沒有意義,但是private方法又不能被重寫 -> 矛盾 * 2. final 和 abstract 不能共存: final修飾的方法不能被重寫 * 3. static 和 abstract 不能共存: static方法也不能被重寫,因為static方法屬于類 */ public class XiuShiFuDemo {public static void main(String[] args) {} } abstract class A{abstract void method01(); //沒有{}方法體,前面沒有public,只有接口默認有publicprivate static void method02(){ //可以,只能在本類里讓其他方法調用如下}static void method03(){ method02();} } package com.itheima04.review; //這部分代碼面板效果如下圖 public class Demo02 {public static void main(String[] args) {} } interface MyInterface{int I = 1; //public static final //final修飾可以用構造賦值,但interface沒構造,寫完就賦初始值void method(); // public abstract } abstract class MyClass{public int id1;protected int id2;int id3;private int id4; public MyClass(){}public static int id5;public final int id6 = 1;public static final int id7 = 1;public String method(int a, int b){return "";}public abstract void method2(); } class F extends MyClass{@Overridepublic void method2() {} }抽象方法:半粉色。f:黃色屬性
8.native:調用C/C++
package com.atguigu.test02; /** native:也是一個修飾符* 1、意思:原生的、本地的* 2、可以修飾什么?可以修飾方法* 3、它修飾的方法有什么不同?* 語法格式:* 【修飾符】 class 類{* 【其他修飾符】 native 返回值類型 方法名(【形參列表】);* }* native修飾的方法,看不見方法體。* native修飾的方法,不是用Java語言實現的,而是調用了底層C/C++的代碼,這些代碼* 被編譯為.dll文件(windows下.dll,linux下是.lib文件),讓Java來執行。 * * (1)native方法,對于Java程序員來說,該怎么調用還怎么調用* (2)子類還可以選擇對它進行重寫*/ public class TestNative {public static void main(String[] args) {Object obj = new Object();System.out.println(obj.hashCode());// 151.....MyClass ob = new MyClass(); //不能為obj和上面同名System.out.println(ob.hashCode());// 1} } class MyClass extends Object{//重寫父類的native方法@Overridepublic int hashCode() {return 1;} }D:\development\jdk1.8\jre\bin 文件夾里有很多.dll文件。
總結
以上是生活随笔為你收集整理的【Java4】实例初始化,类初始化,/接口,多态,final/static,权限修饰符/native的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java3】封装,对象数组,构造器,t
- 下一篇: 【Java5】String类,Strin