以前咋們寫main方法的時候,使用過了一個static關鍵字,接下來咱們來學習一下static關鍵字java
static關鍵字概述程序員
static關鍵字的使用數組
static是靜態修飾符,表示靜態的意思,能夠修飾成員變量和成員方法以及代碼塊。ide
當 static
修飾成員變量時,該變量稱爲類變量。該類的每一個對象都共享同一個類變量的值。任何對象均可以更改該類變量的值,但也能夠在不建立該類的對象的狀況下對類變量進行操做。工具
定義格式:學習
static 數據類型 變量名;
舉例:測試
static String room;
好比說,同窗們來黑馬程序員學校學習,那麼咱們全部同窗的學校都是黑馬程序員, 不因每一個同窗不一樣而不一樣。this
因此,咱們能夠這樣定義一個靜態變量school,代碼以下:atom
public class Student {
private String name;
private int age;
// 類變量,記錄學生學習的學校
public static String school = "黑馬程序員學校";
public Student(String name, int age){
this.name = name;
this.age = age;
}
// 打印屬性值
public void show() {
System.out.println("name=" + name + ", age=" + age + ", shool=" + shool );
}
}
public class StuDemo {
public static void main(String[] args) {
Student s1 = new Student("張三", 23);
Student s2 = new Student("李四", 24);
Student s3 = new Student("王五", 25);
Student s4 = new Student("趙六", 26);
s1.show(); // Student : name=張三, age=23, shool=學校
s2.show(); // Student : name=李四, age=24, shool=學校
s3.show(); // Student : name=王五, age=25, shool=學校
s4.show(); // Student : name=趙六, age=26, shool=學校
}
}
當static
修飾成員方法時,該方法稱爲類方法 。靜態方法在聲明中有static
,建議使用類名來調用,而不須要建立類的對象。調用方式很是簡單。spa
類方法:使用 static關鍵字修飾的成員方法,習慣稱爲靜態方法。
定義格式:
修飾符 static 返回值類型 方法名 (參數列表){
// 執行語句
}
舉例:在Student類中定義靜態方法
public static void showNum() {
System.out.println("num:" + numberOfStudent);
}
靜態方法調用的注意事項:
靜態方法能夠直接訪問類變量和靜態方法。
靜態方法不能直接訪問普通成員變量或成員方法。成員方法能夠直接訪問類變量或靜態方法。
靜態方法中,不能使用this關鍵字。
小貼士:靜態方法只能訪問靜態成員。
被static修飾的成員能夠而且建議經過類名直接訪問。雖然也能夠經過對象名訪問靜態成員,緣由即多個對象均屬於一個類,共享使用同一個靜態成員,可是不建議,會出現警告信息。
格式:
// 訪問類變量
類名.類變量名;
// 調用靜態方法
類名.靜態方法名(參數);
調用演示,代碼以下:
public class StuDemo2 {
public static void main(String[] args) {
// 訪問類變量
System.out.println(Student.numberOfStudent);
// 調用靜態方法
Student.showNum();
}
}
小結:static修飾的內容是屬於類的,能夠經過類名直接訪問
概述 : 被static修飾的代碼塊,就叫作靜態代碼塊
靜態代碼塊:定義在成員位置,使用static修飾的代碼塊{ }。
位置:類中方法外。
執行:隨着類的加載而執行且執行一次,優先於main方法和構造方法的執行。
格式:
static {
// 靜態代碼塊
}
例如:
public class Student {
static {
// 靜態代碼塊
System.out.println("靜態代碼塊執行了...");
}
public Student() {
System.out.println("Student類的空參構造方法執行了...");
}
}
public class StaticDemo {
static {
// 靜態代碼塊
System.out.println("main方法所在的類中的靜態代碼塊執行了...");
}
public static void main(String[] args) {
/*
靜態代碼塊:定義在成員位置,使用static修飾的代碼塊{ }。
- 位置:類中方法外。
- 執行:隨着類的加載而執行且執行一次,優先於main方法和構造方法的執行。
*/
System.out.println("main方法中的代碼...");
// new Student();
// new Student();
}
}
之後的項目中,一般會須要一些「全局變量」或者「全局的工具方法」,這些全局變量和方法,能夠單獨定義在一個類中,並聲明爲static(靜態)的,能夠很方便的經過類名訪問
例如:
public class Utils{
public static double pi = 3.14159;
public static int getMax(int[] arr) {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
max = arr[i] > max ? arr[i] : max;
}
return max;
}
}
public class Demo {
public static void main(String[] args) {
System.out.println("全局的PI值:" + Utils.pi);
int[] arr = {1, 443243, 4, 3243, 4324};
int max = Utils.getMax(arr);
System.out.println("最大值:" + max);
}
}
略
引用數據類型除了類其實還有接口,接下來學習接口的概述
接口的概述
接口,是Java語言中一種引用類型,是方法的集合,若是說類的內部封裝了成員變量、構造方法和成員方法,那麼接口的內部主要就是封裝了方法,包含抽象方法(JDK 7及之前),默認方法和靜態方法(JDK 8)。
接口的定義,它與定義類方式類似,可是使用 interface
關鍵字。它也會被編譯成.class文件,但必定要明確它並非類,而是另一種引用數據類型。
public class 類名.java-->.class
public interface 接口名.java-->.class
引用數據類型:數組,類,接口。
接口的使用,它不能建立對象,可是能夠被實現(implements
,相似於被繼承)。一個實現接口的類(能夠看作是接口的子類),須要實現接口中全部的抽象方法,建立該類對象,就能夠調用方法了,不然它必須是一個抽象類。
略
如何定義一個接口
定義格式的格式
public interface 接口名稱 {
// 常量
// 抽象方法
// 默認方法
// 靜態方法
}
接口中的常量: 使用 public static final修飾,能夠省略
例如:
public static final int NUM = 10;// NUM就是一個常量
抽象方法:使用abstract
關鍵字修飾,能夠省略,沒有方法體。該方法供子類實現使用。
代碼以下:
public interface InterFaceName {
public abstract void method();
}
默認方法:使用 default
修飾,不可省略,供子類調用或者子類重寫。
靜態方法:使用 static
修飾,供接口直接調用。
代碼以下:
public interface InterFaceName {
public default void method() {
// 執行語句
}
public static void method2() {
// 執行語句
}
}
小結:定義接口時就是將定義類的class改爲了interface,而且接口中的內容也有了一些變化。
接口定義的格式
如何建立已定義好的接口類型的對象呢?
實現的概述
抽象方法的使用
默認方法的使用
靜態方法的使用
類與接口的關係爲實現關係,即類實現接口,該類能夠稱爲接口的實現類,也能夠稱爲接口的子類。實現的動做相似繼承,格式相仿,只是關鍵字不一樣,實現使用 implements
關鍵字。
非抽象子類實現接口:
必須重寫接口中全部抽象方法。
繼承了接口的默認方法,便可以直接調用,也能夠重寫。
抽象子類實現接口: 能夠無需重寫接口中的抽象方法
實現格式:
class 類名 implements 接口名 {
// 重寫接口中抽象方法【必須】
// 重寫接口中默認方法【可選】
}
必須所有實現,代碼以下:
定義接口:
public interface LiveAble {
// 定義抽象方法
public abstract void eat();
public abstract void sleep();
}
定義實現類:
public class Animal implements LiveAble {
定義測試類:
public class InterfaceDemo {
public static void main(String[] args) {
// 建立子類對象
Animal a = new Animal();
// 調用實現後的方法
a.eat();
a.sleep();
}
}
輸出結果:
吃東西
晚上睡
能夠繼承,能夠重寫,二選一,可是隻能經過實現類的對象來調用。
繼承默認方法,代碼以下:
定義接口:
public interface LiveAble {
public default void fly(){
System.out.println("天上飛");
}
}
定義實現類:
public class Animal implements LiveAble {
// 繼承,什麼都不用寫,直接調用
}
定義測試類:
public class InterfaceDemo {
public static void main(String[] args) {
// 建立子類對象
Animal a = new Animal();
// 調用默認方法
a.fly();
}
}
輸出結果:
天上飛
重寫默認方法,代碼以下:
定義接口:
public interface LiveAble {
public default void fly(){
System.out.println("天上飛");
}
}
定義實現類:
public class Animal implements LiveAble {
定義測試類:
public class InterfaceDemo {
public static void main(String[] args) {
// 建立子類對象
Animal a = new Animal();
// 調用重寫方法
a.fly();
}
}
輸出結果:
自由自在的飛
靜態與.class 文件相關,只能使用接口名調用,不能夠經過實現類的類名或者實現類的對象調用,代碼以下:
定義接口:
public interface LiveAble {
public static void run(){
System.out.println("跑起來~~~");
}
}
定義實現類:
public class Animal implements LiveAble {
// 沒法重寫靜態方法
}
定義測試類:
public class InterfaceDemo {
public static void main(String[] args) {
// Animal.run(); // 【錯誤】沒法繼承方法,也沒法調用
LiveAble.run(); //
}
}
輸出結果:
跑起來~~~
小結: 類實現接口使用的是implements關鍵字,而且一個普通類實現接口,必需要重寫接口中的全部的抽象方法
略
以前學過,在繼承體系中,一個類只能繼承一個父類。而對於接口而言,一個類是能夠實現多個接口的,這叫作接口的多實現。而且,一個類能繼承一個父類,同時實現多個接口。
抽象方法
默認方法
靜態方法
父類中的成員方法與接口中的默認方法重名優先級問題
class 類名 [extends 父類名] implements 接口名1,接口名2,接口名3... {
// 重寫接口中抽象方法【必須】
// 重寫接口中默認方法【不重名時可選】
}
[ ]: 表示可選操做。
接口中,有多個抽象方法時,實現類必須重寫全部抽象方法。若是抽象方法有重名的,只須要重寫一次。代碼以下:
定義多個接口:
interface A {
public abstract void showA();
public abstract void show();
}
interface B {
public abstract void showB();
public abstract void show();
}
定義實現類:
public class C implements A,B{
接口中,有多個默認方法時,實現類均可繼承使用。若是默認方法有重名的,必須重寫一次。代碼以下:
定義多個接口:
interface A {
public default void methodA(){}
public default void method(){}
}
interface B {
public default void methodB(){}
public default void method(){}
}
定義實現類:
public class C implements A,B{
接口中,存在同名的靜態方法並不會衝突,緣由是隻能經過各自接口名訪問靜態方法。
當一個類,既繼承一個父類,又實現若干個接口時,父類中的成員方法與接口中的默認方法重名,子類就近選擇執行父類的成員方法。代碼以下:
定義接口:
interface A {
public default void methodA(){
System.out.println("AAAAAAAAAAAA");
}
}
定義父類:
class D {
public void methodA(){
System.out.println("DDDDDDDDDDDD");
}
}
定義子類:
class C extends D implements A {
// 未重寫methodA方法
}
定義測試類:
public class Test {
public static void main(String[] args) {
C c = new C();
c.methodA();
}
}
輸出結果:
DDDDDDDDDDDD
小結: 一個類能夠實現多個接口,多個接口之間使用逗號隔開便可。
略
接口的多繼承
接口的多繼承
其餘成員特色
一個接口能繼承另外一個或者多個接口,這和類之間的繼承比較類似。接口的繼承使用 extends
關鍵字,子接口繼承父接口的方法。若是父接口中的默認方法有重名的,那麼子接口須要重寫一次。代碼以下:
定義父接口:
interface A {
public default void method(){
System.out.println("AAAAAAAAAAAAAAAAAAA");
}
}
interface B {
public default void method(){
System.out.println("BBBBBBBBBBBBBBBBBBB");
}
}
定義子接口:
interface D extends A,B{
小貼士:
子接口重寫默認方法時,default關鍵字能夠保留。
子類重寫默認方法時,default關鍵字不能夠保留。
小結:接口和接口之間是繼承的關係,而不是實現。一個接口能夠繼承多個接口。
略
接口中,沒法定義成員變量,可是能夠定義常量,其值不能夠改變,默認使用public static final修飾。
接口中,沒有構造方法,不能建立對象。
接口中,沒有靜態代碼塊。
抽象類和接口的練習
案例描述
案例分析
案例代碼實現
經過實例進行分析和代碼演示抽象類和接口的用法。
一、舉例:
犬:
行爲:
吼叫;
吃飯;
緝毒犬:
行爲:
吼叫;
吃飯;
緝毒;
二、思考:
因爲犬分爲不少種類,他們吼叫和吃飯的方式不同,在描述的時候不能具體化,也就是吼叫和吃飯的行爲不能明確。當描述行爲時,行爲的具體動做不能明確,這時,能夠將這個行爲寫爲抽象行爲,那麼這個類也就是抽象類。
但是有的犬還有其餘額外功能,而這個功能並不在這個事物的體系中 , 例如 : 緝毒犬。緝毒的這個功能有好多種動物都有 , 例如 : 緝毒豬 , 緝毒鼠。咱們能夠將這個額外功能定義接口中 ,讓緝毒犬繼承犬且實現緝毒接口 , 這樣緝毒犬既具有犬科自身特色也有緝毒功能。
//定義緝毒接口 緝毒的詞組(anti-Narcotics)比較長,在此使用拼音替代
interface JiDu{
//緝毒
public abstract void jiDu();
}
//定義犬科,存放共性功能
abstract class Dog{
//吃飯
public abstract void eat();
//吼叫
public abstract void roar();
}
//緝毒犬屬於犬科一種,讓其繼承犬科,獲取的犬科的特性,
//因爲緝毒犬具備緝毒功能,那麼它只要實現緝毒接口便可,這樣即保證緝毒犬具有犬科的特性,也擁有了緝毒的功能
class JiDuQuan extends Dog implements JiDu{
public void jiDu() {
}
void eat() {
}
void roar() {
}
}
//緝毒豬
class JiDuZhu implements JiDu{
public void jiDu() {
}
}
講完抽象類和接口後,相信有許多同窗會存有疑惑,二者的共性那麼多,只留其中一種不就好了,這裏就得知道抽象類和接口從根本上解決了哪些問題.
一個類只能繼承一個直接父類(多是抽象類),卻能夠實現多個接口, 接口彌補了Java的單繼承
抽象類爲繼承體系中的共性內容, 接口爲繼承體系中的擴展功能
接口仍是後面一個知識點的基礎(lambada)
略
多態的概述
引入
概念
造成多態的條件
多態是繼封裝、繼承以後,面向對象的第三大特性。
生活中,好比跑的動做,小貓、小狗和大象,跑起來是不同的。再好比飛的動做,昆蟲、鳥類和飛機,飛起來也是不同的。可見,同一行爲,經過不一樣的事物,能夠體現出來的不一樣的形態。多態,描述的就是這樣的狀態。
多態: 是指同一行爲,具備多個不一樣表現形式。
繼承或者實現【二選一】
方法的重寫【意義體現:不重寫,無心義】
父類引用指向子類對象【格式體現】
略
如何實現多態
多態的體現
多態體現的格式:
父類類型 變量名 = new 子類對象;
變量名.方法名();
父類類型:指子類對象繼承的父類類型,或者實現的父接口類型。
代碼以下:
Fu f = new Zi();
f.method();
當使用多態方式調用方法時,首先檢查父類中是否有該方法,若是沒有,則編譯錯誤;若是有,執行的是子類重寫後方法。
代碼以下:
定義父類:
public abstract class Animal {
public abstract void eat();
}
定義子類:
class Cat extends Animal {
public void eat() {
System.out.println("吃魚");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨頭");
}
}
定義測試類:
public class Test {
public static void main(String[] args) {
// 多態形式,建立對象
Animal a1 = new Cat();
// 調用的是 Cat 的 eat
a1.eat();
// 多態形式,建立對象
Animal a2 = new Dog();
// 調用的是 Dog 的 eat
a2.eat();
}
}
多態在代碼中的體現爲父類引用指向子類對象。
略
掌握多態時訪問成員的特色
多態時成員變量的訪問特色
多態時成員方法的訪問特色
多態時成員變量的訪問特色
編譯看左邊,運行看左邊
簡而言之:多態的狀況下,訪問的是父類的成員變量
多態時成員方法的訪問特色
非靜態方法:編譯看左邊,運行看右邊
簡而言之:編譯的時候去父類中查找方法,運行的時候去子類中查找方法來執行
靜態方法:編譯看左邊,運行看左邊
簡而言之:編譯的時候去父類中查找方法,運行的時候去父類中查找方法來執行
注意:多態的狀況下是沒法訪問子類獨有的方法
演示代碼:
public class Demo1 {
public static void main(String[] args) {
// 父類的引用指向子類的對象
Animal anl1 = new Dog();
// 訪問非靜態方法
anl1.eat();
// 訪問成員變量num
System.out.println(anl1.num);//10
// 訪問靜態方法
anl1.sleep();
// 多態想要調用子類中獨有的方法
// anl1.lookHome(); 錯誤的,沒法訪問 多態的弊端:沒法訪問子類獨有的方法
}
}
public class Animal {
int num = 10;
public void eat(){
System.out.println("吃東西...");
}
public static void sleep(){
System.out.println("Animal類中的睡覺方法...");
}
}
public class Dog extends Animal {
int num = 20;
// 重寫
public void eat() {
System.out.println("狗吃骨頭");
}
public static void sleep(){
System.out.println("Dog類中的睡覺方法...");
}
public void lookHome(){
System.out.println("狗正在看家...");
}
}
略
多態的幾種表現形式
普通父類多態
抽象父類多態
父接口多態
多態的表現形式:
普通父類多態
public class Fu{}
public class Zi extends Fu{}
public static void main(String[] args){
Fu f = new Zi();//左邊是一個「父類」
}
抽象父類多態
public abstract class Fu{}
public class Zi extends Fu{}
public static void main(String[] args){
Fu f = new Zi();//左邊是一個「父類」
}
父接口多態
public interface A{}
public class AImp implements A{}
public static void main(String[] args){
A a = new AImp();
}
略
掌握多態在開發中的應用場景
變量多態
形參多態
返回值多態
定義一個Animal類,讓Dog和Cat類繼承Animal類:
public class Animal {
public void eat(){
System.out.println("吃東西...");
}
}
public class Cat extends Animal {
多態的幾種應用場景:
public class Demo1 {
public static void main(String[] args) {
/*
多態的應用場景:
1.變量多態
2.形參多態
3.返回值多態
*/
// 1.變量多態
Animal anl = new Dog();
anl.eat();
// 2.形參多態
Dog dog = new Dog();
invokeEat(dog);
Cat cat = new Cat();
invokeEat(cat);// 實參賦值給形參: Animal anl = new Cat();
// 3.返回值多態
Animal anl2 = getAnimal();// 返回值賦值給變量: Animal anl2 = new Dog()
}
// 3.返回值多態
// 結論:若是方法的返回值類型爲父類類型,那麼就能夠返回該父類對象以及其全部子類對象
public static Animal getAnimal(){
// return new Animal();
return new Dog();
// return new Cat();
}
// 形參多態: 當你調用invokeEat方法的時候,傳入Animal類的子類對象
// Animal anl = dog; ====> Animal anl = new Dog();
// 結論:若是方法的參數是父類類型,那麼就能夠接收全部該父類對象以及其全部子類對象
// Object類:是java中全部類的父類,因此若是參數爲Object類型,那麼就能夠傳入一切類的對象
public static void invokeEat(Animal anl){
anl.eat();
}
}
略
實際開發的過程當中,父類類型做爲方法形式參數,傳遞子類對象給方法,進行方法的調用,更能體現出多態的擴展性與便利。
多態的好處和弊端
代碼以下:
定義父類:
public abstract class Animal {
public abstract void eat();
}
定義子類:
class Cat extends Animal {
public void eat() {
System.out.println("吃魚");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨頭");
}
}
定義測試類:
public class Test {
public static void main(String[] args) {
// 多態形式,建立對象
Cat c = new Cat();
Dog d = new Dog();
// 調用showCatEat
showCatEat(c);
// 調用showDogEat
showDogEat(d);
/*
以上兩個方法, 都可以被showAnimalEat(Animal a)方法所替代
而執行效果一致
*/
showAnimalEat(c);
showAnimalEat(d);
}
public static void showCatEat (Cat c){
c.eat();
}
public static void showDogEat (Dog d){
d.eat();
}
public static void showAnimalEat (Animal a){
a.eat();
}
}
因爲多態特性的支持,showAnimalEat方法的Animal類型,是Cat和Dog的父類類型,父類類型接收子類對象,固然能夠把Cat對象和Dog對象,傳遞給方法。
當eat方法執行時,多態規定,執行的是子類重寫的方法,那麼效果天然與showCatEat、showDogEat方法一致,因此showAnimalEat徹底能夠替代以上兩方法。
不只僅是替代,在擴展性方面,不管以後再多的子類出現,咱們都不須要編寫showXxxEat方法了,直接使用showAnimalEat均可以完成。
因此,多態的好處,體如今,可使程序編寫的更簡單,並有良好的擴展。
小結:多態的好處是提升程序的靈活性,擴展性
多態的弊端: 沒法訪問子類的獨有方法
多態的轉型分爲向上轉型與向下轉型
向上轉型
向下轉型
向上轉型:多態自己是子類類型向父類類型向上轉換的過程,這個過程是默認的。
當父類引用指向一個子類對象時,即是向上轉型。
使用格式:
父類類型 變量名 = new 子類類型();
如:Animal a = new Cat();
向下轉型:父類類型向子類類型向下轉換的過程,這個過程是強制的。
一個已經向上轉型的子類對象,將父類引用轉爲子類引用,可使用強制類型轉換的格式,即是向下轉型。
使用格式:
子類類型 變量名 = (子類類型) 父類變量名;
如:Cat c =(Cat) a;
當使用多態方式調用方法時,首先檢查父類中是否有該方法,若是沒有,則編譯錯誤。也就是說,不能調用子類有而父類沒有的方法。編譯都錯誤,更別說運行了。這也是多態給咱們帶來的一點"小麻煩"。因此,想要調用子類特有的方法,必須作向下轉型。
轉型演示,代碼以下:
定義類:
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃魚");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨頭");
}
public void watchHouse() {
System.out.println("看家");
}
}
定義測試類:
public class Test {
public static void main(String[] args) {
// 向上轉型
Animal a = new Cat();
a.eat(); // 調用的是 Cat 的 eat
// 向下轉型
Cat c = (Cat)a;
c.catchMouse(); // 調用的是 Cat 的 catchMouse
}
}
轉型的過程當中,一不當心就會遇到這樣的問題,請看以下代碼:
public class Test {
public static void main(String[] args) {
// 向上轉型
Animal a = new Cat();
a.eat(); // 調用的是 Cat 的 eat
// 向下轉型
Dog d = (Dog)a;
d.watchHouse(); // 調用的是 Dog 的 watchHouse 【運行報錯】
}
}
這段代碼能夠經過編譯,可是運行時,卻報出了 ClassCastException
,類型轉換異常!這是由於,明明建立了Cat類型對象,運行時,固然不能轉換成Dog對象的。這兩個類型並無任何繼承關係,不符合類型轉換的定義。
爲了不ClassCastException的發生,Java提供了 instanceof
關鍵字,給引用變量作類型的校驗,格式以下:
變量名 instanceof 數據類型
若是變量屬於該數據類型,返回true。
若是變量不屬於該數據類型,返回false。
因此,轉換前,咱們最好先作一個判斷,代碼以下:
public class Test {
public static void main(String[] args) {
// 向上轉型
Animal a = new Cat();
a.eat(); // 調用的是 Cat 的 eat
// 向下轉型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 調用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 調用的是 Dog 的 watchHouse
}
}
}
小結:多態向上轉型是將子類類型轉成父類類型,多態向下轉型是將父類類型轉成子類類型。
內部類的概述
什麼是內部類
成員內部類的格式
成員內部類的訪問特色
將一個類A定義在另外一個類B裏面,裏面的那個類A就稱爲內部類,B則稱爲外部類。
成員內部類 :定義在類中方法外的類。
定義格式:
class 外部類 {
class 內部類{
}
}
在描述事物時,若一個事物內部還包含其餘事物,就可使用內部類這種結構。好比,汽車類Car
中包含發動機類Engine
,這時,Engine
就可使用內部類來描述,定義在成員位置。
代碼舉例:
class Car { //外部類
class Engine { //內部類
}
}
內部類能夠直接訪問外部類的成員,包括私有成員。
外部類要訪問內部類的成員,必需要創建內部類的對象。
建立內部類對象格式:
外部類名.內部類名 對象名 = new 外部類型().new 內部類型();
訪問演示,代碼以下:
定義類:
public class Person {
private boolean live = true;
class Heart {
public void jump() {
// 直接訪問外部類成員
if (live) {
System.out.println("心臟在跳動");
} else {
System.out.println("心臟不跳了");
}
}
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
}
定義測試類:
public class InnerDemo {
public static void main(String[] args) {
// 建立外部類對象
Person p = new Person();
// 建立內部類對象
Person.Heart heart = p.new Heart();
// 調用內部類方法
heart.jump();
// 調用外部類方法
p.setLive(false);
// 調用內部類方法
heart.jump();
}
}
輸出結果:
心臟在跳動
心臟不跳了
內部類仍然是一個獨立的類,在編譯以後會內部類會被編譯成獨立的.class文件,可是前面冠之外部類的類名和$符號 。
好比,Person$Heart.class
小結:內部類是定義在一個類中的類。
匿名內部類
匿名內部類的概述
匿名內部類的格式
匿名內部類 :是內部類的簡化寫法。它的本質是一個帶具體實現的
父類或者父接口的
匿名的
子類對象。
開發中,最經常使用到的內部類就是匿名內部類了。以接口舉例,當你使用一個接口時,彷佛得作以下幾步操做,
定義子類
重寫接口中的方法
建立子類對象
調用重寫後的方法
咱們的目的,最終只是爲了調用方法,那麼能不能簡化一下,把以上四步合成一步呢?匿名內部類就是作這樣的快捷方式。
存在一個類或者接口,這裏的類能夠是具體類也能夠是抽象類。
new 父類名或者接口名(){
// 方法重寫
以接口爲例,匿名內部類的使用,代碼以下:
定義接口:
public abstract class FlyAble{
public abstract void fly();
}
匿名內部類能夠經過多態的形式接受
public class InnerDemo01 {
public static void main(String[] args) {
/*
1.等號右邊:定義並建立該接口的子類對象
2.等號左邊:是多態,接口類型引用指向子類對象
*/
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飛了~~~");
}
};
}
}
匿名內部類直接調用方法
public class InnerDemo02 {
public static void main(String[] args) {
/*
1.等號右邊:定義並建立該接口的子類對象
2.等號左邊:是多態,接口類型引用指向子類對象
*/
new FlyAble(){
public void fly() {
System.out.println("我飛了~~~");
}
}.fly();
}
}
方法的形式參數是接口或者抽象類時,也能夠將匿名內部類做爲參數傳遞
public class InnerDemo3 {
public static void main(String[] args) {
/*
1.等號右邊:定義並建立該接口的子類對象
2.等號左邊:是多態,接口類型引用指向子類對象
*/
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飛了~~~");
}
};
// 將f傳遞給showFly方法中
showFly(f);
}
public static void showFly(FlyAble f) {
f.fly();
}
}
以上能夠簡化,代碼以下:
public class InnerDemo2 {
public static void main(String[] args) {
/*
建立匿名內部類,直接傳遞給showFly(FlyAble f)
*/
showFly( new FlyAble(){
public void fly() {
System.out.println("我飛了~~~");
}
});
}
public static void showFly(FlyAble f) {
f.fly();
}
}
匿名內部類作的事情是建立一個類的子類對象
實際的開發中,引用類型的使用很是重要,也是很是廣泛的。咱們能夠在理解基本類型的使用方式基礎上,進一步去掌握引用類型的使用方式。基本類型能夠做爲成員變量、做爲方法的參數、做爲方法的返回值,那麼固然引用類型也是能夠的。在這咱們使用兩個例子 , 來學習一下。
引用類型做爲方法參數和返回值
引用類型做爲成員變量
public class Person{
public void eat(){
System.out.println("吃飯");
}
}
public class Test{
public static void main(String[] args){
method(new Person());
Person p = createPerson();
}
//引用類型做爲方法參數,在前面筆記本案例中咱們也使用了接口類型做爲方法參數
pubic static void method(Person p){
p.eat();
}
//引用類型做爲返回值
public static Person createPerson(){
return new Person();
}
}
咱們每一個人(Person)都有一個身份證(IDCard) , 爲了表示這種關係 , 就須要在Person中定義一個IDCard的成員變量。定義Person類時,代碼以下:
class Person {
String name;//姓名
int age;//年齡
}
使用使用String
類型表示姓名 , int
類型表示年齡。其實,String
自己就是引用類型,咱們每每忽略了它是引用類型。若是咱們繼續豐富這個類的定義,給Person
增長身份證號 , 身份證簽發機關等屬性,咱們將如何編寫呢?這時候就須要編寫一個IDCard類了
定義IDCard(身份證)類,添加身份證號 , 簽發地等屬性:
class IDCard {
String idNum;//身份證號
String authority;//簽發地
//getter和setter方法
//...
//toString方法
//...
}
修改Person類:
public class Person {
String name;//姓名
int age;//年齡
IDCard idCard;//表示本身的身份證信息
//name和age的getter、setter方法
//...
public IDCard getIdCard() {
return idCard;
}
public void setIdCard(IDCard idCard) {
this.idCard = idCard;
}
測試類:
public class TestDemo {
public static void main(String[] args) {
//建立IDCard對象
IDCard idCard = new IDCard();
//設置身份證號
idCard.setIdNum("110113201606066666");
//設置簽發地
idCard.setAuthority("北京市順義區公安局");
//建立Person對象
Person p = new Person();
//設置姓名
p.setName("小順子");
//設置年齡
p.setAge(2);
//設置身份證信息
p.setIdCard(idCard);
//打印小順子的信息
System.out.println(p);
}
}
輸出結果:
Person{name='小順子', age=2, idCard=IDCard{idNum='110113201606066666', authority='北京市順義區公安局'}}