內部類
內部類概念:在一個類的內部再定義一個完整的類.
特點: 編譯之後可生成獨立的字節碼文件。
內部類可直接訪問外部類的私有成員,而不破壞封裝。
可爲外部類提供必要的內部功能組件。
成員內部類
成員內部類:也稱實例內部類
-
在類的內部定義,與實例變量、實例方法同級別的類。
-
外部類的一個實例部分,創建內部類對象時,必須依賴外部類對象。
-
當外部類、內部類存在重名屬性時,會優先訪問內部類屬性
-
成員內部類不能定義靜態成員
1.成員內部類在實例層級——加載成員內部類中內容是在外部類對象被創建時。
package com.qf.day19.text;
/*
* 案例1,成員內部類
*/
public class TestInstanceInnerClass {
public static void main(String[] args) {
}
}
class Outer{
int a =10;//實例變量
public void m1() {//實例方法
}
//成員內部類(實例層級)
class Inner{
}
}
- 成員內部類對象的創建,依賴於外部類對象的創建。
成員內部類與外部類實例變量及方法是同一層級。
成員內部類可直接訪問外部類實例變量 //1 私有成員變量也可直接訪問,並不破壞封裝//4。
成員內部類與外部類屬性重名時,優先訪問內部類屬性//2。
若仍需獲取外部類實例變量時則可通過//3(特殊、不具普適性)訪問外部內實例變量。
/*
* 案例1,成員內部類
*/
public class TestInstanceInnerClass {
public static void main(String[] args) {
Outer out = new Outer();
//1. Outer.Inner in = new Outer.Inner();
//2.實質上
Outer.Inner in = out.new Inner();
in.m2();
}
}
class Outer{
private int a =10;//實例變量//1 改爲私有成員變量//4
public void m1() {//實例方法
}
//成員內部類(實例層級)
class Inner{
int a =20;
public void m2() {
System.out.println(a);//2
System.out.println("Class Inner m2()"+a);
System.out.println(Outer.this.a);//訪問外部實例變量//3 特殊、不具普適性
}
}
}
3.成員內部類中不能定義靜態成員//5,內部類屬實例層級需要依賴於對象才能訪問其值,但靜態成員可用//6Outer.Inner.s;的方式來獲取屬性值,兩者矛盾。不能定義靜態成員,不能脫離外部類對象而獨立存在。
/*
* 案例1,成員內部類
*/
public class TestInstanceInnerClass {
public static void main(String[] args) {
Outer out = new Outer();
//1. Outer.Inner in = new Outer.Inner();
//2.實質上
Outer.Inner in = out.new Inner();
in.m2();
Outer.Inner.s;//6
}
}
class Outer{
private int a =10;//實例變量//1 改爲私有成員變量//4
public void m1() {//實例方法
}
//成員內部類(實例層級)
class Inner{
int a =20;
static String s = "Null_kun";//5不能定義靜態成員,不能脫離外部類對象而獨立存在
public void m2() {
System.out.println(a);//2
System.out.println("Class Inner m2()"+a);
System.out.println(Outer.this.a);//訪問外部實例變量//3
}
}
}
靜態內部類
-
不依賴外部類對象,可直接創建或通過類名訪問,可聲明靜態成員。
-
只能直接訪問外部類的靜態成員。(實例成員需實例化外部類對象)。
1.不依賴外部類對象,可直接創建或通過類名訪問,可聲明靜態成員。
//1訪問類中的靜態屬性 類名.屬性名 //2.訪問靜態內部類中屬性,即靜態內部類是外部類靜態屬性之一 //3創建內部類實例對象 //4使用靜態內部類中的方法需先創建對象
public class TestStaticClass {
public static void main(String[] args) {
System.out.println(Outer.a);//1訪問類中的靜態屬性 類名.屬性名
System.out.println(Outer.Inner.b);//2.訪問靜態內部類中屬性,即靜態內部類是外部類靜態屬性之一
Outer.Inner in = new Outer.Inner();//3創建內部類實例對象
in.m2();//4使用靜態內部類中的方法需先創建對象
}
}
class Outer{
static int a = 10;
static class Inner{ //靜態內部類
static int b =20;
public void m2() {
System.out.println("Inner.m2()");
}
}
}
-
//5靜態內部類只能直接訪問外部類的靜態成員,//6外部類靜態成員私有也可直接訪問。 //7靜態內部類中並直接訪問外部類中的實例變量,靜態不能訪問非靜態實例變量。 //*比靜態代碼塊功能更豐富。
public class TestStaticClass {
public static void main(String[] args) {
//System.out.println(Outer.a);//1訪問類中的靜態屬性 類名.屬性名
System.out.println(Outer.Inner.b);//2.訪問靜態內部類中屬性,即靜態內部類是外部類靜態屬性之一
Outer.Inner in = new Outer.Inner();//3創建內部類實例對象
in.m2();//4使用靜態內部類中的方法需先創建對象
}
}
class Outer{
private static int a = 10;//6外部內靜態成員私有
String s = "hello";//實例對象
static class Inner{ //靜態內部類
static int b =20;
public void m2() {
System.out.println(Outer.a);//5.訪問外部類靜態屬性
System.out.println("Inner.m2()");
System.out.println(Outer.s);//7訪問外部類實例變量不行
}
}
}
局部內部類
-
定義在外部類方法中,作用範圍和創建對象範圍僅限於當前方法。
-
局部內部類訪問外部類當前方法中的局部變量時,因無法保證變量的生命週期與自身相同,變量必須修飾爲final。
-
限制類的使用範圍。
1. //1定義在外部內的方法中,只有當方法執行,纔會執行局部內部類,即方法執行完畢前建內部類對象
//2 只有創建外部類對象並執行內部類所在的方法,才執行局部內部類中代碼。
//3.局部內部類中訪問外部類的實例成員
//4.局部內部類中訪問內部類的實例成員
//5.局部內部類訪問外部類的局部變量
*//6 給m1方法中局部變量賦值,訪問局部變量報錯。JDK8以前版本中,int b 就會編譯錯誤,必須將其修飾爲final,JDK8會隱式加上final。
public class TestLocalInner {
public static void main(String[] args) {
Outer out = new Outer();
out.m1();//2 只有創建外部類對象並執行內部類所在的方法
}
}
class Outer{
int a =10;//實例變量
public void m1() {//外部類實例方法
int b =20;//局部變量
//b=88;//6.賦值 變量b必須是final修飾的常量
class Inner{//局部內部類
int c =30;
public void m2() {
System.out.println(Outer.this.a);//3.訪問外部類的實例成員
System.out.println(this.c);//4.訪問內部類的實例成員
System.out.println(b);//5.局部內部類訪問外部類的局部變量
System.out.println("Inner m2()");
}
}
Inner in = new Inner(); //1
System.out.println(in.c);
in.m2();
}
public void m3() {}
}
- 存活週期JVM棧<Heap堆<方法區,局部內部類在內存中無對象或子類了纔會回收。Inner對象在方法內的變量就必須在。
3.局部內部類繼承接口。驗證在外部實例方法結束後依然能存儲局部變量值,若不加final局部變量生命週期早已結束。
public class TestLocalInner {
public static void main(String[] args) {
Outer out = new Outer();
out.m1();//只有創建外部類對象並執行內部類所在的方法
System.out.println(out.p);
out.p.print();
}
}
class Outer{
printable p=null;
int a =10;//實例變量
public void m1() {//外部類實例方法
int b =20;//局部變量
class Inner implements printable{//局部內部類
public void print() {
System.out.println(b);//局部內部類訪問外部類的局部變量
}
}
p= new Inner();
}
}
interface printable{
public void print();
}
4.限制類的使用範圍
4.1例如:若實現分班,但依然無法規避家長直接new教師,因爲此時校方的內部規則,仍然是公開類。教師信息沒有對外界隱藏所以家長可自己new
public class TestInnerLocalForApply {
public static void main(String[] args) {
//學校開設新班
/*1.
Teacher teacher = new AdvancedTeacher();//家長提出意見需要高級教師
teacher.teach();//問題就是校方沒辦法提供如此多的高級教師
*/
//校方出臺了內部規則(按照班級的奇偶編號進行均勻分派,奇數初級,偶數高級)
Teacher t =School.getTeacher(1);
t.teach();
}
}
class School{
public static Teacher getTeacher(int classNo) {//使用靜態方法,無需new School
Teacher currentTeacher = null;
if(classNo%2 !=0) {
currentTeacher = new BeginnerTeacher();
}else {
currentTeacher = new AdvancedTeacher();
}
return currentTeacher;
}
}
abstract class Teacher{
public abstract void teach();
}
class BeginnerTeacher extends Teacher{
@Override
public void teach() {
System.out.println("初級老師在上課");
}
}
class AdvancedTeacher extends Teacher{
@Override
public void teach() {
System.out.println("高級老師在上課");
}
}
4.2 初高級教師類定義在getTeacher方法中。利用抽象類實現高級封裝,隱藏類的信息。
public class TestInnerLocalForApply {
public static void main(String[] args) {
//學校開設新班
/*1.
Teacher teacher = new AdvancedTeacher();//家長提出意見需要高級教師
teacher.teach();//問題就是校方沒辦法提供如此多的高級教師
*/
//校方出臺了內部規則(按照班級的奇偶編號進行均勻分派,奇數初級,偶數高級)
Teacher t =School.getTeacher(1);
t.teach();
Teacher t1 =School.getTeacher(2);
t1.teach();
}
}
class School{
public static Teacher getTeacher(int classNo) {//使用靜態方法,無需new School
class BeginnerTeacher extends Teacher{
@Override
public void teach() {
System.out.println("初級老師在上課");
}
}
class AdvancedTeacher extends Teacher{
@Override
public void teach() {
System.out.println("高級老師在上課");
}
}
Teacher currentTeacher = null;
if(classNo%2 !=0) {
currentTeacher = new BeginnerTeacher();
}else {
currentTeacher = new AdvancedTeacher();
}
return currentTeacher;
}
}
abstract class Teacher{
public abstract void teach();
}
匿名內部類
- 沒有類名的局部內部類(一切特徵都與局部內部類相同)
- 必須繼承一個父類或者實現一個接口
- 定義類、實現類、創建對象的語法合併,只能創建一個該類的對象(類信息只用到一次)
- 優點:減少代碼量,書寫思路流程。(編程思路可方便new對象)
- 缺點:可讀性較差
例如4.3:將初高級教師的類和其中實現以及創建此類合併,修改4.2中實例匿名內部類。
public class TestInnerLocalForApply {
public static void main(String[] args) {
//學校開設新班
/*1.
Teacher teacher = new AdvancedTeacher();//家長提出意見需要高級教師
teacher.teach();//問題就是校方沒辦法提供如此多的高級教師
*/
//校方出臺了內部規則(按照班級的奇偶編號進行均勻分派,奇數初級,偶數高級)
Teacher t =School.getTeacher(1);
t.teach();
Teacher t1 =School.getTeacher(2);
t1.teach();
}
}
class School{
public static Teacher getTeacher(int classNo) {//使用靜態方法,無需new School
Teacher currentTeacher = null;
if(classNo%2 !=0) {
currentTeacher = new Teacher() {
@Override
public void teach() {
System.out.println("初級老師在上課");
}
};
}else {
currentTeacher = new Teacher() {
@Override
public void teach() {
System.out.println("高級老師在上課");
}
};
}
return currentTeacher;
}
}
abstract class Teacher{
public abstract void teach();
}