day02【final、靜態、多態】
昨日反饋和回顧
能夠寫出類的繼承格式
public class 子類 extends 父類{
}
能夠說出Java繼承的特點
a.單繼承(一個子類只能有一個父類,一個父類可以有多個子類)
b.多層繼承(一個子類可以有一個父類,該父類也可以有自己的父類)
能夠說出子類調用父類的成員特點
如果子父類中有同名的成員變量/成員方法,根據Java就近原則,優先調用子類自己成員
如果子父類中不同名的成員變量/成員方法,根據變量或者方法名字調用,不存在歧義
構造方法,a.父類的構造子類無法繼承 b.在子類的任何構造第一行,默認調用父類的無參構造,super()
夠說出方法重寫的概念
方法重載(overload): 在同一個類中,方法名一樣的,參數列表不一樣
方法重寫(override): 在繼承關係中,子類中有一個和父類除了方法體(權限修飾符),其他一模一樣的方法
能夠說出this可以解決的問題
在本類中使用:
this.xxx 訪問本類的成員變量
this.xxx() 調用本類的成員方法
this(...) 調用本類的其他構造
能夠說出super可以解決的問題
在子類中使用:
super.xxx 訪問父類繼承的成員變量
super.xxx() 調用父類繼承的成員方法
super(...) 調用父類構造方法
描述抽象方法的概念
抽象方法: 只有方法的聲明,沒有方法的實現(加上關鍵字abstract)
抽象類: 含有抽象方法的類一定是一個抽象類
如果是一個抽象類,其中不一定含有抽象方法
寫出抽象類的格式
public abstract class 抽象類名{
抽象方法
正常方法
}
寫出抽象方法的格式
public abstract void 抽象方法名();
能夠說出父類抽象方法的存在意義
抽象類的意義: 給其他子類繼承的,爲子類提供模板(模板設計模式)
抽象方法的意義: 要求子類必須重寫(如果不重寫,子類還是一個抽象類)
今日內容介紹
a.關鍵字final
b.關鍵字static
c.引用類型_接口(重點)
第一章 final關鍵字
1.1 final關鍵字
final什麼意思: 最終的,不可變的
final在Java中是一個修飾符:
修飾類,修飾方法,修飾局部變量,修飾成員變量,修飾引用類型變量
1.2 final的作用介紹
-
final修飾類
被final修飾的類,我們稱爲太監類,不能被繼承 /** * 父類 */ public final class Fu { } /** * 子類報錯了,因爲父類是final類,不能被繼承 */ public class Zi extends Fu { } 注意: final修飾的類沒有子類,並不是說它不能繼承別的類
-
final修飾方法
被final修飾的方法,不能被重寫!! /** * 父類 */ public class Fu { //final修飾方法 public final void show() { System.out.println("show..."); } } /** * 子類 */ public class Zi extends Fu{ //重寫報錯!!! //因爲父類的show方法是final修飾的,子類不允許重寫 @Override public void show() { System.out.println("重寫後的show..."); } }
-
final修飾局部變量
被final修飾的局部變量,表示該變量只能賦值一次 public class TestDemo { public static void main(String[] args) { //定義一個局部變量 //給它加上final修飾 final int num = 10; //報錯了!! 因爲final修飾的局部變量,只能賦值一次 num = 20; num = 30; num = 40; System.out.println(num); } } 注意: final int num = 10; 這句代碼也可以寫出以下兩句 final int num; num = 10; 這也是OK的!!
思考:如下兩種寫法,哪種可以通過編譯?
寫法1: 報錯!! final int c = 0; //只能賦值一次 for (int i = 0; i < 10; i++) { c = i; // 第二次賦值了,報錯!!! System.out.println(c); } 寫法2: 編譯通過! for (int i = 0; i < 10; i++) { final int c = i; //c也是final修飾的 //因爲c是在循環體中定義的,每次循環都是新的一個c System.out.println(c); }
-
final修飾引用類型的變量
final修飾引用類型的變量,表示該引用類型變量中保存的地址值不能改變量 public class Dog { int age = 10; String name = "旺財"; } public class TestDog { public static void main(String[] args) { //1.創建一個引用類型的變量 // 給引用類型的變量也叫上final final Dog d = new Dog(); // d中是對象的地址 0x111 //報錯的!!!!因爲final修飾d,表示d中地址值不能改變 d = new Dog(); //將d中的對象地址 改爲 0x222 } } 注意: final修飾d只表示d中地址不能改變,並不代表d中的成員變量值不能改變, 以下寫法是正確的: d.age = 20; d.name = "來福";
-
final修飾成員變量
被final修飾的成員變量,只能賦值一次,必須賦值 但是賦值可以有兩種選擇: a.定義該成員變量的時候賦值 public class Student { //使用final修飾成員變量 final int age = 10; } b.或者在構造方法中給該成員變量賦值 public class Student { //使用final修飾成員變量 final int age; //在構造方法中賦值 public Student(){ this.age = 20; } } 總之,final修飾的成員變量,必須在創建對象之前有值
第二章 static關鍵字
2.1 概述
static什麼意思: 靜態關鍵字
static也是一個修飾符,用於修飾類中成員變量/成員方法,被static修飾的成員我們稱之爲靜態成員/類成員
"被static修飾的成員,不屬於任何一個對象,屬於整個類,被所有對象共享"
2.2 定義和使用格式
-
類變量
類變量:就是使用static修飾的成員變量,我們稱爲類變量/靜態變量 "被static修飾的成員變量,不屬於任何一個對象,屬於整個類,被所有對象共享" /** * 學生類 */ public class Student { int age; String name; //靜態變量,類變量,在內存的方法區中的靜態區,只有一份(所有對象共享它) static String school = "黑馬程序員"; public void show(){ System.out.println("姓名:"+name+",年齡:"+age+",學校:"+school); } } public class TestStudent { public static void main(String[] args) { //1.第一個學生 Student s1 = new Student(); s1.name = "孫嘉華"; s1.age = 18; s1.show(); System.out.println("============"); //2.第二個學生 Student s2 = new Student(); s2.name = "趙廣順"; s2.age = 35; s2.show(); System.out.println("============="); //孫嘉華同學去了"傳智專修學院" //修改了靜態區中的共享變量,所有對象訪問時,都能看到修改後的結果 s1.school = "傳智專修學院"; System.out.println("============="); s1.show(); s2.show(); } }
-
靜態方法
靜態方法也叫類方法,由static修飾的方法 特點: 正常的方法必須通過對象才能調用,靜態方法不需要通過對象,通過類名就可以直接調用 /** * 計算器類 */ public class Calculator { //計算兩個數的和 //這就是靜態方法/類方法 public static int getSum(int a, int b) { return a + b; } } public class TestCalculator { public static void main(String[] args) { //1.創建對象 // Calculator cc = new Calculator(); // int sum = cc.getSum(111, 999); // System.out.println("求和爲:"+sum); //2.靜態方法,直接通過類名調用即可 int sum = Calculator.getSum(111, 999); System.out.println("求和爲:"+sum); } }
2.3 靜態和非靜態之間的相互調用
靜態成員變量
靜態成員方法
與類是同級,只要類加載到內存,靜態的成員變量/成員方法就存在(對象不一定存在)
非靜態成員變量
非靜態成員方法
必須創建對象之後才能訪問/調用
生命週期看:
靜態出現的比非靜態要早!!!!
結論:
a.靜態與靜態之間,非靜態與非靜態之間是可以相互訪問的
b.非靜態可以訪問靜態,但是靜態不能訪問非靜態
靜態的: 秦始皇(出現早)
非靜態: 我們(出現晚)
2.4 建議調用格式
靜態的成員變量
對象名.靜態的成員變量 【可以訪問的,但是我們不建議】
類名.靜態的成員變量 【建議訪問的方式】
靜態的成員方法
對象名.靜態的成員方法() 【可以訪問的,但是我們不建議】
類名.靜態的成員方法() 【建議訪問的方式】
總結: 靜態成員雖然可以通過對象名去訪問/調用,但是我們更建議直接使用類名去訪問/調用
第三章 接口【重要】
3.1 概述
什麼是接口:
也是一種引用類型,接口是方法的集合(接口中主要寫方法)
3.2 定義格式
定義類: class
定義接口: interface
定義枚舉: enum 【以後講解】
定義註解: @interface 【以後講解】
格式:
public interface 接口名{
//抽象方法【JDK7】
//默認方法和靜態方法【JDK8】
//私有方法和私有靜態方法【JDK9瞭解】
}
/**
* 定義接口的格式
*/
public interface MyInterface {
//抽象方法【主要】,只有接口中抽象方法 public abstract 關鍵字可以省略(省略不代表沒有,編譯器會自動添加)
public abstract void abs1();
public abstract void abs2();
//默認方法
//使用一個關鍵字修飾 default
public default void m1(){
System.out.println("接口中的默認方法1");
}
public default void m2(){
System.out.println("接口中的默認方法2");
}
//靜態方法
//使用一個關鍵字 static
public static void s1(){
System.out.println("接口中的靜態方法1");
}
public static void s2(){
System.out.println("接口中的靜態方法2");
}
}
3.3 接口的使用
a.和抽象類類似,接口也是不能創建的對象的
b.接口也是作爲父接口使用的,用於被其他類"實現"的
c.繼承使用extends關鍵字,實現使用"implements"關鍵字
使用方式:
public class 實現類 implements 接口名{
//a.必須重寫接口中所有的抽象方法
//b.選擇性重寫接口中的默認方法,但是重寫後不能有default
//c.靜態方法沒有重寫的說法,因爲它是通過所在類/接口的名字直接調用的
}
/**
* 實現類
*/
public class MyClass implements MyInterface {
//a.實現類 必須 重寫接口中的所有抽象方法
@Override
public void abs1() {
System.out.println("重寫後的abs1...");
}
@Override
public void abs2() {
System.out.println("重寫後的abs2...");
}
//b.實現類 可以 選擇性重寫默認方法,但是重寫後不能加default
@Override
public void m1() {
System.out.println("重寫後的m1方法..");
}
//c.靜態方法通過類名/接口名 直接調用的,沒有重寫這種說法
public static void s1(){
System.out.println("實現類中的靜態方法1");
}
}
測試類
public class TestDemo {
public static void main(String[] args) {
//1.創建實現類對象
MyClass mc = new MyClass();
//2.抽象方法
mc.abs1();
mc.abs2();
//3.默認方法
mc.m1(); //調用實現類的重寫方法
mc.m2(); //調用接口中的默認方法
//4.靜態方法
MyInterface.s1(); // 接口的s1
MyClass.s1(); // 實現類的s1
}
}
3.4 接口的多實現
格式:
public class 實現類 implements 接口1,接口2,..{
//a.實現類需要重寫所有接口中的所有抽象方法
//如果有抽象方法是一樣的,那麼實現類只需要重寫一次
//b.實現類可以選擇性重寫所有接口中的默認方法
//如果接口中有一樣的默認方法,實現類必須重寫一次
//c.靜態方法沒有重寫的概念,就算多個接口中有一樣的靜態方法
//也不衝突,通過各位所在的接口名調用,沒有歧義
}
/**
* 實現類:多實現
*/
public class MyClass implements MyInter1,MyInter2{
//1.抽象方法
//實現類必須重寫所有接口中的所有抽象方法
//如果有抽象方法是一樣的,那麼實現類只需要重寫一次
@Override
public void abs1() {
System.out.println("實現類重寫後的抽象方法1..");
}
@Override
public void abs2() {
System.out.println("實現類重寫後的抽象方法2...");
}
//abs方法
@Override
public void abs() {
System.out.println("實現類重寫後的抽象方法s");
}
//2.默認方法
//實現類可以選擇性重寫所有接口中的默認方法
//如果接口中有一樣的默認方法,實現類必須重寫一次
@Override
public void show() {
System.out.println("實現類重寫後的默認方法show...");
}
//3.靜態方法
//靜態方法沒有重寫的概念,就算多個接口中有一樣的靜態方法
//也不衝突,通過各位所在的接口名調用,沒有歧義
//通過MyInter1.s()和通過MyInter2.s()
public static void s(){
System.out.println("實現類自己的s方法");
}
}
public class TestDemo {
public static void main(String[] args) {
//創建實現類對象
MyClass mc = new MyClass();
//1.抽象方法
mc.abs1();
mc.abs2();
mc.abs();
//2.默認方法
mc.show1(); //調用接口1的默認方法show1
mc.show2(); //調用接口2的默認方法show2
mc.show(); //調用實現類重寫後的show
//3.靜態方法
MyInter1.s();
MyInter2.s();
MyClass.s();
}
}
3.5 實現和繼承的優先級問題
一個類 可以在繼承一個父類的同時實現多個接口(繼承和實現可以同時存在)
格式:
public class 子類/實現類 extends 父類 implements 接口,...{
}
繼承的優先級 高於 實現,所以必須先extends後implements
public interface MyInter {
//默認方法
public default void show(){
System.out.println("接口的默認方法");
}
}
public class Fu {
//正常方法
public void show(){
System.out.println("父類的show方法");
}
}
public class Zi extends Fu implements MyInter{
//如果父類中的正常方法和接口中的默認方法一樣了
//a.那麼子類需要不需要對同名的show方法進行重寫呢??
//子類可以不重寫該方法,調用優先調用父類中的show
//b.那麼子類能不能重寫show方法呢???
//可以重寫,重寫後,優先調用子類重寫後的方法
@Override
public void show() {
System.out.println("子類重寫後的show...");
}
}
public class TestDemo {
public static void main(String[] args) {
//1.創建子類對象
Zi zz = new Zi();
zz.show();
}
}
3.6 接口的多繼承【瞭解】
類和類之間: 單繼承
類和接口之間: 多實現
接口和接口之間: 多繼承
格式:
public interface MyInter extends Inter1,Inter2{
MyInter接口包含Inter1和Inter2接口所有東西
}
接口多繼承我們只做瞭解即可,我們在開會中很少寫這種代碼
public class MyClass implements MyInter{
}
和
public class MyClass implements Inter1,Inter2{
}
效果是一樣
3.7 接口中其他成員特點
a.接口中,無法定義成員變量,但是可以定義常量(字面值常量,由public static fina修飾的常量)
其值不可以改變,默認使用public static final修飾(可省略,但是編譯器會自動添加)
【public static final】 數據類型 常量名 = 值; 【常量名一般純大寫,多個單詞之間使用_分隔】
b.接口中,沒有構造方法,不能創建對象。
c.接口中,沒有靜態代碼塊【明後天講解】
3.8 抽象類和接口的練習
案例介紹:
代碼實現
/**
* 狗類,所有狗的共性內容
*/
public class Dog {
int age;
String name;
public void bark(){
System.out.println("小狗汪汪~~~");
}
public void run(){
System.out.println("小狗旺旺~~~");
}
}
/**
* 緝毒接口,其中包含緝毒抽象方法
*/
public interface JiDu {
//緝毒抽象方法
public abstract void jiDu();
}
/**
* 超級狗(緝毒狗)
*/
public class SuperDog extends Dog implements JiDu{
//必須重寫接口的緝毒方法
@Override
public void jiDu() {
System.out.println("旺旺,站住,別跑,否則老子開搶了...");
}
}
public class TestDemo {
public static void main(String[] args) {
//1.創建一個緝毒狗
SuperDog superDog = new SuperDog();
//2.調用方法
superDog.bark();
superDog.run();
superDog.jiDu();
}
}
總結
描述final
修飾類: 該類不能被繼承
修飾方法: 該方法不能被重寫
修飾變量: 該變量只能賦值一次
局部變量: 可以在定義時賦值,可以先定義後賦值
成員變量: 可以在定義時賦值,可以在構造方法中賦值
引用類型變量: 表示該引用類型變量的地址值不能改變,但是地址內成員變量的值是可以改變
能夠掌握static關鍵字修飾的變量調用方式
類名.成員變量名【建議的使用方式】
能夠掌握static關鍵字修飾的方法調用方式
類名。成員方法名() 【建議的使用方式】
能夠寫出接口的定義格式
public interface 接口名{
//抽象方法【我們最最最常寫】
//默認方法
//靜態方法
}
能夠寫出接口的實現格式
public class 實現類 implements 接口名,...{
//a.重寫所有抽象方法,如果有相同只需要重寫一次
//b.選擇性重寫默認方法,如果相同必須重寫一次
//c.靜態方法沒有重寫的概念
}
能夠說出接口中的其他成員特點
a.沒有成員變量,只有常量
[public static final] 數據類型 常量名 = 值;
b.沒有構造方法,也不能創建對象
c.也沒有靜態代碼塊[明後天搞定!]