權限類內同包不同包子類不同包非子類
private
√
×
×
×
default
√
√
×
×
protected
√
√
√
×
public
√
√
√
√
四、super關鍵字的使用
package com.test.java;
/*
* super可以用來修飾屬性、方法、構造器
* 1)當子類與父類中有同名的屬性時,可以通過"super.屬性"顯式的調用父類中聲明的屬性。用"this.屬性"調用子類中聲明的屬性
* 2)當子類重寫父類的方法以后,在子類中想再顯式的調用父類的被重寫的方法,需要用"super.方法來調用"
* 3)super修飾構造器:通過在子類中使用"super(形參列表)"來顯式的調用父類的構造器
* >在構造器內部,"super(形參列表)"必須要聲明在首行
* >在構造器內部,"this.(形參列表)"與"super(形參列表)"只能出現一個
* >當構造器中,不顯式的調用this()或者super()其中任何一個,默認調用的是父類的空參構造器
* 如果父類沒有聲明空參構造器,或者只聲明了帶參數的構造器(這時空參構造器自動作廢),在子類
* 中會報錯
* 建議:在設計一個類時,盡量提供一個空參構造器。
*/
public class Person {
public String name;
public Person() {//父類構造器
this.name = "Father";
System.out.println(this.name);
}
public void eat() {
System.out.println("父類吃飯");
}
}
class Student extends Person{
public String name;
public Student() {//子類構造器,經過main方法測試,調用子類構造器之前會自動調用父類構造器
//相當于這里有一個 Super();
this.name = "Son";
super.name = "SuperFather";//在子類中調用父類的
System.out.println(this.name+super.name);
}
public void eat() {
System.out.println("子類吃飯");
super.eat();//在子類中用super調用父類的重名方法,重寫(覆蓋)并不等于將父類的方法刪除掉。
}
}
五、子類對象實例化
class Creature{
public Creature(){
System.out.println("Creature無參數的構造器");
}
}
class Animal extends Creature{
public Animal(String name){
System.out.println("Animal帶一個參數的構造器,該動物的name為" + name);
}
public Animal(String name , int age){
this(name);
System.out.println("Animal帶兩個參數的構造器,其age為" + age);
}
}
public class Wolf extends Animal{
public Wolf(){
super("灰太狼", 3);
System.out.println("Wolf無參數的構造器");
}
public static void main(String[] args){
new Wolf();
} }
從創建Wolf對象開始,調用Wolf構造器,Wolf構造器調用父類Animal的兩個參數的構造器,兩個參數的構造器再調用一個參數的構造器,一個參數的構造器再調用父類Creature的構造器,Creature構造器調用Object類中的構造器,然后再逆向執行回來,最后一個被調用的構造器最先執行,依次向下執行構造器中的內容,像對象中的toString方法等就是再Object類中的某個方法,任何一個類調用構造器都會以最后一個Object類結束。
六、多態性
package com.xijian.java;
/*
* 多態的應用舉例
* 總結:通過向上轉型來引用父類方法(在子類未重寫方法的前提下),通過向下轉型來引用子類獨有的方法
* 向下轉型實際就是在棧空間聲明一個子類引用類型的變量指向棧空間的父類引用對象,通過父類引用對象進而指向堆空間,對對象進行操作。
* 訪問權限是由引用變量類型決定的。
*/
public class TestAnimal {
public static void main(String[] args) {
Animal a = new Dog();//可以擴大對象被調用的權限
Animal b = new Cat();//可以擴大對象被調用的權限
TestAnimal test = new TestAnimal();
test.func(a);
test.func(b);
}
public void func(Animal a) {
a.eat();
a.jump();
if(a instanceof Dog) {
Dog d = (Dog)a;//向下轉型,用新的引用類型去引用子類存在而父類不存在的方法
d.say();
}
if(a instanceof Cat) {
Cat c = (Cat)a;//向下轉型,用新的引用類型去引用子類存在而父類不存在的方法
c.say();
c.name = "1";
System.out.println(a.name);//通過測試可以看出,向下轉型使用新的引用類型可以對子類對象進行操作
}
}
}
class Animal{
String name;
int age;
public void eat() {
System.out.println("進食");
}
public void jump() {
System.out.println("jump");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("狗進食");
}
public void jump() {
System.out.println("狗急跳墻");
}
public void say() {
System.out.println("狗叫");
}
}
class Cat extends Animal{
public void eat() {
System.out.println("貓進食");
}
public void jump() {
System.out.println("貓跳");
}
public void say() {
System.out.println("貓叫");
}
}
多態性:多態就是指程序中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在編程時并不確定,而是在程序運行期間才確定,即一個引用變量倒底會指向哪個類的實例對象,該引用變量發出的方法調用到底是哪個類中實現的方法,必須在由程序運行期間才能決定。因為在程序運行時才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實現上,從而導致該引用調用的具體方法隨之改變,即不修改程序代碼就可以改變程序運行時所綁定的具體代碼,讓程序可以選擇多個運行狀態,這就是多態性。
1)如果我們定義了一個指向子類的父類引用類型,那么它除了能夠引用父類的共性外,還可以使用子類強大的功能,這就是向上轉型。
父類名稱 引用對象名稱 = new 子類對象名稱();
指向子類的父類引用由于向上轉型了,它只能訪問父類中擁有的方法和屬性,而對于子類中存在而父類中不存在的方法,該引用是不能使用的,盡管是重載該方法。若子類重寫了父類中的某些方法,在調用該些方法的時候,必定是使用子類中定義的這些方法(動態連接、動態調用)。()
2)如果在向上轉型之后想訪問子類中獨有的方法,需要向下轉型,向下轉型實際就是在棧空間聲明一個子類引用類型的變量指向棧空間的父類引用對象,通過父類引用對象進而指向堆空間,對對象進行操作。
子類名稱 新引用對象名稱 = (子類名稱)需轉型的對象名;
3)子類對象的多態性,并不適用于屬性!
在調用屬性的時候,只是看的是調用對象的引用類型,如果這個對象的引用類型是父類的,那么調父類的屬性,如果是個子類的引用類型,則調子類對應的屬性,并不存在多態性。
4)判斷對象屬于哪種類型的
if(obj instanceof class){}
其返回true情況如下
1.obj是class類的對象
2.obj是class類子類的對象
多態性在Java上有兩種體現
①方法的重載和重寫:同名方法可以通過形參列表的不同和子父類的繼承關系來同時顯示。
②對象的多態性:子類的對象可以賦給父類/父接口的引用。
七、所有的類的頂級類Object
package com.xijian.java;
public class Testequals {
public static void main(String[] args) {
//==
//1.基本數據類型:根據基本數據類型的值判斷是否相等。相等返回true,否則返回false
//注:兩端數據類型可以不同,在不同的情況下也可以返回true
int i = 12;
int j = 12;
System.out.println(i==j);//true
char c = 12;
System.out.println(i==c);//true
float f = 12.0F;
System.out.println(i==f);//true
int k = 65;
char a = 'A';
System.out.println(k==a);//true
//2.引用數據類型:比較引用類型變量的地址值是否相等。
Object obj1 = new Object();
Object obj2 = new Object();
Object obj3 = new Object();
obj3 = obj1;
System.out.println(obj1==obj2);//false
System.out.println(obj1==obj3);//true
//equals():①只能處理引用類型對象,并且比較的是兩個對象的地址值是否相等
System.out.println(obj1.equals(obj2));
System.out.println(obj1.equals(obj3));
//像String類 包裝類 File類 Date類重寫了Object類里的equals方法
//比較的是兩個對象中的具體內容是否相同
String str1 = new String("AA");
String str2 = new String("AA");
System.out.println(str1.equals(str2));//true
}
}
Object是Java中所有類的頂級類。
①在Java中,==表示等于,=表示賦值。
當==兩側比較的是基本數據類型時,由基本數據類型的值判斷二者是否相等,相等則返回true,不等在返回false。需要注意的是,兩側的基本數據類型即使類型不同,也會返回true,如:int i =65,char j=12;char a ='A';則i==j==a全部返回true。
當兩側是引用數據類型時,兩側比較的是引用變量的地址值,相等返回true,不等返回false。
②equals方法
equals方法只可以處理引用數據類型的變量,在object類中,equals方法仍然是比較兩個引用變量的地址值是否相同;所以要想用equals方法比較object類子類的實體內容,就必須要重寫object類的equals方法。
③String類在內存中的分析
翻看String類的源代碼我們可以知道:它是不可繼承的(final修飾類),線程安全的(?????),值不可變(兩個成員變量都有final修飾,指針可變),本質上是一個字符數組。
我們知道創建string類對象的時候,一般由三種方式:
使用關鍵字new,如:String s1 = new String(“myString”);
直接定義,如:String s1 = “myString”;
串聯生成,如:String s1 = “my” + “String”
第一種使用關鍵字new創建的String類對象時,編譯程序回先在字符串常量池中查看有沒有“myString”這個字符串,若有,則在堆中開辟一塊空間存放new出來的實例,指向常量池中的"myString",在棧中開辟一塊區域存放s1這個引用變量,指向堆中的new出來的實例;若沒有,則在常量池中創建一個"myString"字符串。
第二種方式直接定義過程:在程序編譯期,編譯程序先去字符串常量池檢查,是否存在“myString”,如果不存在,則在常量池中開辟一個內存空間存放“myString”;如果存在的話,則不用重新開辟空間。然后在棧中開辟一塊空間,命名為“s1”,存放的值為常量池中“myString”的內存地址
第三種,改變的不是字符串,而是相當于重新創建了一個新的字符串,重新有一個地址值。
相對于new出來的字符串來說,直接賦值的方式效率好,因為它只在字符串常量池開辟了一個內存空間,而new出來的相當于開辟了兩個內存空間,耗費內存。
④toString()方法的使用
當我們打印一個引用變量的對象時,默認會調用這個對象的toString方法。
如果對象所在的類沒有重寫Object中的toString方法,那么調用的就是Object中的toString方法,打印出全類名+@+首地址值。
八、包裝類
將8個基礎數據類型包裝成類之后,就可以調用類中的方法來處理這些數據了。
基本數據類型、包裝類、String類之間的轉換問題
原則:轉換成誰,去誰里邊找轉換方法或者構造器。
① 基本數據類型和包裝數據類型之間的轉換:JDK5.0之后加入了自動裝箱和拆箱的功能。
②基本/包裝數據類型和String數據類型之間的轉換
String-->包裝數據類型:Integer.parseInt(str)
包裝數據類型-->String:i+“ ”