俄羅斯成功發射聯盟 2.1b 火箭,將“碼頭”號節點艙及貨運飛船送入軌道
物件
概述
Java是一種面向物件的高階程式語言。
三大特徵:封裝,繼承,多型
面向物件最重要的兩個概念:類和物件
- 類:相同事物共同特徵的描述。類只是學術上的一個概念並非真實存在的,只能描述一類事物
- 物件:是真實存在的例項, 例項==物件,物件是類的例項化
- 結論:有了類和物件就可以描述萬千世界所有的事物。 必須先有類才能有物件
類
定義
定義格式
修飾符 class 類名{
}
- 類名的首字母建議大寫,滿足駝峰模式,比如 StudentNameCode
- 一個 Java 程式碼中可以定義多個類,按照規範一個 Java 檔案一個類
- 一個 Java 程式碼檔案中,只能有一個類是 public 修飾,public修飾的類名必須成為當前Java程式碼的檔名稱
類中的成分:有且僅有五大成分
修飾符 class 類名{
1.成員變數(Field): 描述類或者物件的屬性資訊的。
2.成員方法(Method): 描述類或者物件的行為資訊的。
3.構造器(Constructor): 初始化一個物件返回。
4.程式碼塊
5.內部類
}
類中有且僅有這五種成分,否則程式碼報錯!
public class ClassDemo {
System.out.println(1);//報錯
}
構造器
構造器格式:
修飾符 類名(形參列表){
}
作用:初始化類的一個物件返回
分類:無引數構造器,有引數構造器
注意:一個類預設自帶一個無引數構造器,寫了有引數構造器預設的無引數構造器就消失,還需要用無引數構造器就要重新寫
構造器初始化物件的格式:類名 物件名稱 = new 構造器
- 無引數構造器的作用:初始化一個類的物件(使用物件的預設值初始化)返回
- 有引數構造器的作用:初始化一個類的物件(可以在初始化物件的時候為物件賦值)返回
包
包:分門別類的管理各種不同的技術,便於管理技術,擴充套件技術,閱讀技術
定義包的格式:package 包名
,必須放在類名的最上面
導包格式:import 包名.類名
相同包下的類可以直接訪問;不同包下的類必須導包才可以使用
封裝
封裝的哲學思維:合理隱藏,合理暴露
封裝最初的目的:提高程式碼的安全性和複用性,元件化
封裝的步驟:
- 成員變數應該私有,用 private 修飾,只能在本類中直接訪問
- 提供成套的 getter 和 setter 方法暴露成員變數的取值和賦值
使用 private 修飾成員變數的原因:實現資料封裝,不想讓別人使用修改你的資料,比較安全
this
this 關鍵字的作用:
- this 關鍵字代表了當前物件的引用
- this 出現在方法中:哪個物件呼叫這個方法 this 就代表誰
- this 可以出現在構造器中:代表構造器正在初始化的那個物件
- this 可以區分變數是訪問的成員變數還是區域性變數
static
基本介紹
Java 是通過成員變數是否有 static 修飾來區分是類的還是屬於物件的。
static 靜態修飾的成員(方法和成員變數)屬於類本身的。
按照有無 static 修飾,成員變數和方法可以分為:
-
成員變數:
- 靜態成員變數(類變數):static 修飾的成員變數,屬於類本身,與類一起載入一次,只有一個,直接用類名訪問即可
- 例項成員變數:無 static 修飾的成員變數,屬於類的每個物件的,與類的物件一起載入,物件有多少個,例項成員變數就載入多少個,必須用類的物件來訪問
-
成員方法:
- 靜態方法:有 static 修飾的成員方法稱為靜態方法也叫類方法,屬於類本身的,直接用類名訪問即可
- 例項方法:無 static 修飾的成員方法稱為例項方法,屬於類的每個物件的,必須用類的物件來訪問
static用法
成員變數的訪問語法:
-
靜態成員變數:只有一份可以被類和類的物件共享訪問
- 類名.靜態成員變數(同一個類中訪問靜態成員變數可以省略類名不寫)
- 物件.靜態成員變數(不推薦)
-
例項成員變數:
- 物件.例項成員變數(先建立物件)
成員方法的訪問語法:
-
靜態方法:有 static 修飾,屬於類
- 類名.靜態方法(同一個類中訪問靜態成員可以省略類名不寫)
- 物件.靜態方法(不推薦,參考 JVM → 執行機制 → 方法呼叫)
-
例項方法:無 static 修飾,屬於物件
- 物件.例項方法
public class Student { // 1.靜態方法:有static修飾,屬於類,直接用類名訪問即可! public static void inAddr(){ } // 2.例項方法:無static修飾,屬於物件,必須用物件訪問! public void eat(){} public static void main(String[] args) { // a.類名.靜態方法 Student.inAddr(); inAddr(); // b.物件.例項方法 // Student.eat(); // 報錯了! Student zbj = new Student(); zbj.eat(); } }
兩個問題
記憶體問題:
-
棧記憶體存放 main 方法和地址
-
堆記憶體存放物件和變數
-
方法區存放 class 和靜態變數(jdk8 以後移入堆)
訪問問題:
- 例項方法是否可以直接訪問例項成員變數?可以的,因為它們都屬於物件
- 例項方法是否可以直接訪問靜態成員變數?可以的,靜態成員變數可以被共享訪問
- 例項方法是否可以直接訪問例項方法? 可以的,例項方法和例項方法都屬於物件
- 例項方法是否可以直接訪問靜態方法?可以的,靜態方法可以被共享訪問
- 靜態方法是否可以直接訪問例項變數? 不可以的,例項變數必須用物件訪問!!
- 靜態方法是否可以直接訪問靜態變數? 可以的,靜態成員變數可以被共享訪問。
- 靜態方法是否可以直接訪問例項方法? 不可以的,例項方法必須用物件訪問!!
- 靜態方法是否可以直接訪問靜態方法?可以的,靜態方法可以被共享訪問!!
繼承
基本介紹
繼承是 Java 中一般到特殊的關係,是一種子類到父類的關係
- 被繼承的類稱為:父類/超類。
- 繼承父類的類稱為:子類。
繼承的作用:
- 提高程式碼的複用,相同程式碼可以定義在父類中
- 子類繼承父類,可以直接使用父類這些程式碼(相同程式碼重複利用)
- 子類得到父類的屬性(成員變數)和行為(方法),還可以定義自己的功能,子類更強大
繼承的特點:
- 子類的全部構造器預設先訪問父類的無引數構造器,再執行自己的構造器
- 單繼承:一個類只能繼承一個直接父類
- 多層繼承:一個類可以間接繼承多個父類(家譜)
- 一個類可以有多個子類
- 一個類要麼預設繼承了 Object 類,要麼間接繼承了 Object 類,Object 類是 Java 中的祖宗類
繼承的格式:
子類 extends 父類{
}
子類不能繼承父類的東西:
- 子類不能繼承父類的構造器,子類有自己的構造器
- 子類是不能可以繼承父類的私有成員的,可以反射暴力去訪問繼承自父類的私有成員
- 子類是不能繼承父類的靜態成員的,子類只是可以訪問父類的靜態成員,父類靜態成員只有一份可以被子類共享訪問,共享並非繼承
public class ExtendsDemo {
public static void main(String[] args) {
Cat c = new Cat();
// c.run();
Cat.test();
System.out.println(Cat.schoolName);
}
}
class Cat extends Animal{
}
class Animal{
public static String schoolName ="seazean";
public static void test(){}
private void run(){}
}
變數訪問
繼承後成員變數的訪問特點:就近原則,子類有找子類,子類沒有找父類,父類沒有就報錯
如果要申明訪問父類的成員變數可以使用:super.父類成員變數,super指父類引用
public class ExtendsDemo {
public static void wmain(String[] args) {
Wolf w = new Wolf();w
w.showName();
}
}
class Wolf extends Animal{
private String name = "子類狼";
public void showName(){
String name = "區域性名稱";
System.out.println(name); // 區域性name
System.out.println(this.name); // 子類物件的name
System.out.println(super.name); // 父類的
System.out.println(name1); // 父類的
//System.out.println(name2); // 報錯。子類父類都沒有
}
}
class Animal{
public String name = "父類動物名稱";
public String name1 = "父類";
}
方法訪問
子類繼承了父類就得到了父類的方法,可以直接呼叫,受許可權修飾符的限制,也可以重寫方法
方法重寫:子類重寫一個與父類申明一樣的方法來覆蓋父類的該方法
方法重寫的校驗註解:@Override
- 方法加了這個註解,那就必須是成功重寫父類的方法,否則報錯
- @Override 優勢:可讀性好,安全,優雅
子類可以擴充套件父類的功能,但不能改變父類原有的功能,重寫有以下三個限制:
- 子類方法的訪問許可權必須大於等於父類方法
- 子類方法的返回型別必須是父類方法返回型別或為其子型別
- 子類方法丟擲的異常型別必須是父類丟擲異常型別或為其子型別
繼承中的隱藏問題:
- 子類和父類方法都是靜態的,那麼子類中的方法會隱藏父類中的方法
- 在子類中可以定義和父類成員變數同名的成員變數,此時子類的成員變數隱藏了父類的成員變數,在建立物件為物件分配記憶體的過程中,隱藏變數依然會被分配記憶體
public class ExtendsDemo {
public static void main(String[] args) {
Wolf w = new Wolf();
w.run();
}
}
class Wolf extends Animal{
@Override
public void run(){}//
}
class Animal{
public void run(){}
}
面試問題
-
為什麼子類構造器會先呼叫父類構造器?
- 子類的構造器的第一行預設 super() 呼叫父類的無引數構造器,寫不寫都存在
- 子類繼承父類,子類就得到了父類的屬性和行為。呼叫子類構造器初始化子類物件資料時,必須先呼叫父類構造器初始化繼承自父類的屬性和行為
- 參考 JVM → 類載入 → 物件建立
class Animal{ public Animal(){ System.out.println("==父類Animal的無引數構造器=="); } } class Tiger extends Animal{ public Tiger(){ super(); // 預設存在的,根據引數去匹配呼叫父類的構造器。 System.out.println("==子類Tiger的無引數構造器=="); } public Tiger(String name){ //super(); 預設存在的,根據引數去匹配呼叫父類的構造器。 System.out.println("==子類Tiger的有引數構造器=="); } }
-
為什麼 Java 是單繼承的?
答:反證法,假如 Java 可以多繼承,請看如下程式碼:
class A{ public void test(){ System.out.println("A"); } } class B{ public void test(){ System.out.println("B"); } } class C extends A , B { public static void main(String[] args){ C c = new C(); c.test(); // 出現了類的二義性!所以Java不能多繼承!! } }
super
繼承後 super 呼叫父類構造器,父類構造器初始化繼承自父類的資料。
總結與拓展:
- this 代表了當前物件的引用(繼承中指代子類物件):this.子類成員變數、this.子類成員方法、this(...)可以根據引數匹配訪問本類其他構造器。
- super 代表了父類物件的引用(繼承中指代了父類物件空間):super.父類成員變數、super.父類的成員方法、super(...)可以根據引數匹配訪問父類的構造器
注意:
- this(...) 借用本類其他構造器,super(...) 呼叫父類的構造器。
- this(...) 或 super(...) 必須放在構造器的第一行,否則報錯!
- this(...) 和 super(...) 不能同時出現在構造器中,因為建構函式必須出現在第一行上,只能選擇一個。
public class ThisDemo {
public static void main(String[] args) {
// 需求:希望如果不寫學校預設就是”張三“!
Student s1 = new Student("天蓬元帥", 1000 );
Student s2 = new Student("齊天大聖", 2000, "清華大學" );
}
}
class Study extends Student {
public Study(String name, int age, String schoolName) {
super(name , age , schoolName) ;
// 根據引數匹配呼叫父類構造器
}
}
class Student{
private String name ;
private int age ;
private String schoolName ;
public Student() {
}
public Student(String name , int age){
// 借用兄弟構造器的功能!
this(name , age , "張三");
}
public Student(String name, int age, String schoolName) {
this.name = name;
this.age = age;
this.schoolName = schoolName;
}
// .......get + set
}
final
基本介紹
final 用於修飾:類,方法,變數
- final 修飾類,類不能被繼承了,類中的方法和變數可以使用
- final 可以修飾方法,方法就不能被重寫
- final 修飾變數總規則:變數有且僅能被賦值一次
面試題:final 和 abstract 的關係是互斥關係,不能同時修飾類或者同時修飾方法!
修飾變數
靜態變數
final 修飾靜態成員變數,變數變成了常量
常量:有 public static final 修飾,名稱字母全部大寫,多個單詞用下劃線連線。
final 修飾靜態成員變數可以在哪些地方賦值:
-
定義的時候賦值一次
-
可以在靜態程式碼塊中賦值一次
public class FinalDemo {
//常量:public static final修飾,名稱字母全部大寫,下劃線連線。
public static final String SCHOOL_NAME = "張三" ;
public static final String SCHOOL_NAME1;
static{
//SCHOOL_NAME = "java";//報錯
SCHOOL_NAME1 = "張三1";
//SCHOOL_NAME1 = "張三2"; // 報錯,第二次賦值!
}
}
例項變數
final 修飾變數的總規則:有且僅能被賦值一次
final 修飾例項成員變數可以在哪些地方賦值 1 次:
- 定義的時候賦值一次
- 可以在例項程式碼塊中賦值一次
- 可以在每個構造器中賦值一次
public class FinalDemo {
private final String name = "張三" ;
private final String name1;
private final String name2;
{
// 可以在例項程式碼塊中賦值一次。
name1 = "張三1";
}
//構造器賦值一次
public FinalDemo(){
name2 = "張三2";
}
public FinalDemo(String a){
name2 = "張三2";
}
public static void main(String[] args) {
FinalDemo f1 = new FinalDemo();
//f1.name = "張三1"; // 第二次賦值 報錯!
}
}