內部類
概念
定義在一個類內部的類叫做內部類
public class Demo3 {
}
class Outer{
//
class Inner{
}
}
特點
每一個類都會生成一個單獨的字節碼文件
分類
1、成員內部類
2、靜態內部類
3、局部內部類
4、匿名內部類(最常用的一個內部類 也是jdk8中新特性Lambda的前提)
一、成員內部類
1、定義位置
外部類的成員位置
2、特點
特點:可以訪問外部類的私有成員⽽不破環封裝
案例:
public class Demo3 {
}
class Outer{
private int a = 10;
private void m(){
System.out.println("我是外部類中的私有成員方法");
}
private static void m2(){
System.out.println("我是外部類中的私有靜態方法");
}
//成員位置
//成員內部類
class Inner {
public void m1(){
System.out.println(a);//可以直接訪問外部類的私有成員而不破環封裝
m();
m2();
}
}
}
3、對象的創建方式
1. 先創建外部類對象
2. 通過外部類對象創建內部類對象
案例
//案例1: 關於成員內部類對象的創建
package com.ujiuye.day13;
public class Demo3 {
public static void main(String[] args) {
//創建成員內部類對象
// 1 創建外部類對象
// Outer outer = new Outer();//有名對象
//new Outer();//匿名對象 只能使用一次
//
// //2 通過外部類的對象 創建內部類的對象
// // 類名 對象名 = new 類名();
// Outer.Inner inner = outer.new Inner();
//簡寫
Outer.Inner inner = new Outer().new Inner();
}
}
class Outer{
private int a = 10;
private void m(){
System.out.println("我是外部類中的私有成員方法");
}
private static void m2(){
System.out.println("我是外部類中的私有靜態方法");
}
//成員位置
//成員內部類 ---> 地位 就相當於 成員變量 和 成員方法的地位 隨着對象的創建而存在
class Inner {
public void m1(){
System.out.println(a);//可以直接訪問外部類的私有成員而不破環封裝
m();
m2();
}
}
}
創建對象方式:
//方式一
// 1 創建外部類對象
Outer outer = new Outer();//有名對象
// 2 通過外部類的對象 創建內部類的對象
// 類名 對象名 = new 類名();
Outer.Inner inner = outer.new Inner();
//方式二
//簡寫
Outer.Inner inner = new Outer().new Inner();
4、注意事項
1. 當內部類存在和外部類成員變量重名問題 通過 外部類.this 訪問外部類的屬性
this. 代表的是本類的引⽤
外部類.this. 代表的是外部類的引⽤
2. 不能在成員內部類中創建靜態成員(因為 成員內部類的角色地位和成員變量是同等,也是隨着外部類的對象創建而存在
但是如果有靜態成員的話 內部類的類加載 先於外部類的類加載 ->矛盾
案例
//案例1: 關於注意事項1
public class Demo3 {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
//調用方法
inner.m1();
}
}
class Outer{
//外部類中成員變量 a
private int a = 10;
//成員內部類 ---> 地位 就相當於 成員變量 和 成員方法的地位 隨着對象的創建而存在
class Inner {
//成員內部類中的成員變量
int a = 20;
public void m1(){
//成員內部類 中局部變量
int a = 30;
//訪問每個a
System.out.println(a);//30
// 在內部類中 本質上有 兩個this 內部類對象的this 外部類對象的引用this
System.out.println(this.a);//默認Inner.this
System.out.println(Inner.this.a);//20
System.out.println(Outer.this.a);//10
}
}
}
//案例2: 關於注意事項2
package com.ujiuye.day13;
public class Demo3 {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
//調用方法
inner.m1();
}
}
class Outer{
//外部類中成員變量 a
private int a = 10;
//成員內部類 ---> 地位 就相當於 成員變量 和 成員方法的地位 隨着對象的創建而存在
class Inner {
//成員內部類中的成員變量
int a = 20;
//static int b = 10;//不可以
// public static void m2(){//不可以的
//
// }
public void m1(){
//成員內部類 中局部變量
int a = 30;
//訪問每個a
System.out.println(a);//30
// 在內部類中 本質上有 兩個this 內部類對象的this 外部類對象的引用this
System.out.println(this.a);//默認Inner.this
System.out.println(Inner.this.a);//20
System.out.println(Outer.this.a);//10
}
}
}
二、 靜態內部類
1、位置
在外部類中,和靜態成員並列 static 修飾的成員內部類
2、語法
static class 類名{
}
3、對象創建方式
語法:外部類類名.內部類類名 對象名 = new 外部類.內部類();
public class Demo3 {
public static void main(String[] args) {
//靜態內部類的對象創建
// 靜態成員 可以通過 類名.直接放完 靜態內部類 也可以通過 外部類. 訪問內部類的類名
// 靜態內部類 什么時候進行初始化? 靜態內部類 隨着 外部類 類加載的的進行而存在
// 沒有必要創建外部類對象 直接通過類名.創建對象
// 類名 對象名 = new 類名(); Outer.Inner 看成一個整體
Outer.Inner inner = new Outer.Inner();
}
}
//外部類
class Outer{
//靜態內部類
static class Inner{
}
}
4、特點
靜態內部類中不能直接訪問外部類⾮靜態的成員
案例
//案例1:
public class Demo3 {
public static void main(String[] args) {
//靜態內部類的對象創建
// 靜態成員 可以通過 類名.直接放完 靜態內部類 也可以通過 外部類. 訪問內部類的類名
// 靜態內部類 什么時候進行初始化? 靜態內部類 隨着 外部類 類加載的的進行而存在
// 沒有必要創建外部類對象 直接通過類名.創建對象
// 類名 對象名 = new 類名(); Outer.Inner 看成一個整體
Outer.Inner inner = new Outer.Inner();
}
}
//外部類
class Outer {
//外部類的屬性
int a = 10;//外部類的成員變量
static int b = 20;//外部類的靜態變量
//外部類的成員方法
public void m1() {
System.out.println("我是外部類的成員方法");
}
//外部類的靜態方法
public static void m2() {
System.out.println("我是外部類的靜態方法");
}
//靜態內部類
static class Inner {
//定義一個內部類的成員方法
public void m3() {
// System.out.println(a);//a是非靜態屬性
// m1();//m1方法是非靜態方法
//非要訪問 外部類的成員變量 和調用成員方法
// 創建外部類的對象
// Outer outer = new Outer();
// System.out.println(outer.a);
// outer.m1();
// System.out.println(b);
// m2();
}
}
}
//案例2:
public class Demo3 {
public static void main(String[] args) {
//靜態內部類的對象創建
// 靜態成員 可以通過 類名.直接放完 靜態內部類 也可以通過 外部類. 訪問內部類的類名
// 靜態內部類 什么時候進行初始化? 靜態內部類 隨着 外部類 類加載的的進行而存在
// 沒有必要創建外部類對象 直接通過類名.創建對象
// 類名 對象名 = new 類名(); Outer.Inner 看成一個整體
Outer.Inner inner = new Outer.Inner();
}
}
//外部類
class Outer {
//外部類的屬性
int a = 10;//外部類的成員變量
static int b = 20;//外部類的靜態變量
//外部類的成員方法
public void m1() {
System.out.println("我是外部類的成員方法");
}
//外部類的靜態方法
public static void m2() {
System.out.println("我是外部類的靜態方法");
}
//靜態內部類
static class Inner {
int a = 10;
static int b = 20;
//定義一個內部類的靜態方法
public static void m3() {
System.out.println(a);
System.out.println(b);
}
}
}
//案例3: 關於重名問題
public class Demo3 {
public static void main(String[] args) {
//靜態內部類的對象創建
// 靜態成員 可以通過 類名.直接放完 靜態內部類 也可以通過 外部類. 訪問內部類的類名
// 靜態內部類 什么時候進行初始化? 靜態內部類 隨着 外部類 類加載的的進行而存在
// 沒有必要創建外部類對象 直接通過類名.創建對象
// 類名 對象名 = new 類名(); Outer.Inner 看成一個整體
Outer.Inner inner = new Outer.Inner();
inner.m();
}
}
//外部類
class Outer {
static int b = 20;//外部類的靜態變量
//靜態內部類
static class Inner {
static int b = 30;
public void m(){
System.out.println(b);//30
System.out.println(this.b);
System.out.println(Inner.b);
System.out.println(Outer.b);
}
}
}
三、 局部內部類(重點)
1、位置
在外部類的⽅法中定義局部內部類, 局部位置 ---> 和 局部變量屬於一個等級
2、語法
//定義外部類
class Outer{
public void m1() {
//定義局部內部類
class Inner{
}
}
}
3、創建對象方式
局部內部類的對象只能在它所在的⽅法中 定義內部類語句之后創建
//案例:
public class Demo3 {
public static void main(String[] args) {
}
}
//外部類
class Outer {
//外部類的成員方法
public void m(){
//局部位置
//局部內部類 ---> 隨着 方法的壓棧而初始化
// 局部內部類的 作用域 從定義行開始 到所在的最近的代碼塊結束
class Inner{
}
//在定義局部內部類之后 才能創建對象
Inner inner = new Inner();
}
}
4、特點
1.在局部內部類中可以訪問外部類中的成員,局部內部類中不可以定義靜態成員
2.局部內部類訪問外部類的局部變量 要求這個局部變量必須是final修飾的 在jdk7中必須加final
jdk8可以不加但是默認是final
//案例:
package com.ujiuye.day13;
public class Demo3 {
public static void main(String[] args) {
}
}
//外部類
class Outer {
int a = 10;
static int b = 20;
public void m1(){
System.out.println("我是外部類的成員方法");
}
public static void m2(){
System.out.println("我是外部類的靜態方法");
}
//外部類的成員方法
public void m(){
//局部位置
//局部內部類 ---> 隨着 方法的壓棧而初始化
// 局部內部類的 作用域 從定義行開始 到所在的最近的代碼塊結束
class Inner{
public void m3(){
System.out.println(a);
System.out.println(b);
m1();
m2();
}
}
}
}
//案例2: 關於特點2
public class Demo3 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m();
}
}
//外部類
class Outer {
int a = 10;//外部類的成員變量
//外部類的成員方法
public void m(){
int a = 20;//外部類的局部變量
class Inner{
public void m3(){
//用不到 外部類中的局部變量 ----> 就是沒有加final
//用到 外部類中的局部變量 ---> 系統在jdk8之后 會默認加fianl 在jdk7之前 需要手動加final才能訪問
System.out.println(a);//局部內部類可以訪問外部類的局部變量
}
}
Inner inner = new Inner();
inner.m3();
}
}
案例3: 重名問題
public class Demo3 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m();
}
}
//外部類
class Outer {
int a = 10;//外部類的成員變量a
//外部類的成員方法
public int m(){
int a = 20;//外部類的局部變量a
class Inner{
int a = 30;//內部類的成員變量a
public void m3(){
int a = 40;//內部類的局部變量a
//System.out.println(a);//40
// System.out.println(this.a);//30
// System.out.println(Inner.this.a);//30
// System.out.println(Outer.this.a);//10
// int a = 20; 這個a沒法訪問
// Outer outer = new Outer();
// int m = outer.m();
// System.out.println(m);
}
}
Inner inner = new Inner();
inner.m3();
return a;
}
}
四、匿名內部類
1、概念
匿名內部類是非靜態內部類的一種特殊情況,匿名內部類沒有類名。優點: 可以讓程序員專注於代碼邏輯的實現,讓編程的思路更加的順利.
2、要求
必須繼承一個類 或者 實現一個接口 ----> 這個類要想寫成匿名內部類的形式 必須要求 有親爹 或者有一個干爹
3、特點
一個匿名內部類只能創建一個對象
案例
import java.util.Scanner;
public class Demo5 {
public static void main(String[] args) {
// 1 可以直接通過學校獲取老師
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入你的學號:");
int code = scanner.nextInt();
Teacher teacher = School.getTeacher(code);
//老師上課
teacher.teach();
//2 老師現在不受學校的監管 -----> 違法 學校不允許
// Liu liu = new Liu();
// liu.teach();
//3 學生還可以 通過去學校里 找到劉老師教Java 但是沒有經過選課系統
// School.Liu liu = new School.Liu();
//
// liu.teach();
// 4站在學生的角度分析
// 對於學生 來說:
}
}
//定義一個學校類
class School{
//功能 根據學號分配老師
public static Teacher getTeacher(int code){
if (code%2 == 0){
//返回了一個 Teacher 接口的實現類對象 只不過這個類沒有名字
return new Teacher(){//類沒有名字了 但是告訴系統 我是誰得兒子
@Override
public void teach() {
System.out.println("教Java");
}
};
}else{
return new Teacher(){
@Override
public void teach() {
System.out.println("教前端");
}
};
}
}
}
//接口
interface Teacher{
//規則
void teach();
}
五、內部類的字節碼文件名的總結
不管是外部類 還是 內部類 經過編譯最終都會形成一個單獨的字節碼文件,字節碼文件名和外部類類名有聯系
1、成員內部類
內部類的字節碼文件名: 外部類類名$內部類類名.class
2、靜態內部類
內部類的字節碼文件名: 外部類類名$內部類類名.class
3、局部內部類
內部類字節碼文件名: 外部類類名$序號內部類類名.class 序號: 從 1開始的
4、匿名內部類
內部類字節碼文件名: 外部類類名$序號.class 序號從 1開始編號