這是我參與8月更文挑戰的第8天,活動詳情查看:8月更文挑戰java
一個事物的內部包含另外一個事物。一個類裏面包含另外一個類,這個類叫內部類,包含它的叫它外部類。markdown
例如:身體和心臟的關係;汽車和引擎的關係。ide
心臟、引擎只有在身體和汽車中才有用。內部類也同樣。post
分類:this
1.成員內部類;spa
2.局部內部類(包括匿名內部類);3d
/* 修飾符 class 外部類名稱{ 修飾符 class 內部類名稱{ ...... } ...... } */
public class Outer {
private String name;
public class Inter{
public void InterMethod(){
System.out.println("內部方法");
System.out.println("姓名:" + name); // 成員內部類能夠訪問外部類屬性
}
}
public void fun1(){
Inter in = new Inter();
in.InterMethod();
}
}
複製代碼
編譯後,這個類的class文件保存在磁盤裏code
在外部類中能夠直接經過 new 對象的方式使用。orm
在其餘類中訪問:對象
1.間接方式:在外部類的方法中使用內部類,而在其餘類中使用就 new 外部類調用這個方法;
/** * 其餘類使用內部類 */
public class OuterDemo1 {
public static void main(String[] args) {
Outer out = new Outer();
out.fun1();
}
}
複製代碼
2.直接方式,直接建立出內部類
公式: 外部類名稱.內部類名稱 對象名 = new 外部類名稱().new 內部類名稱();
public class OuterDemo2 {
public static void main(String[] args) {
Outer.Inter in = new Outer().new Inter();
in.InterMethod();
}
}
複製代碼
問題:在外部類、內部類、內部類方法體出現相同名稱屬性,如何輸出相應的值呢?
解決:
public class OuterDemo3 {
private String name ="外";
class Inter{
private String name = "內";
public void interMethod(){
String name = "方法";
System.out.println(name); // 輸出: 方法,就近原則
System.out.println(this.name); // 輸出: 內
System.out.println(OuterDemo3.this.name); // 輸出: 外
}
}
}
複製代碼
在方法體內定義一個類,出了這個方法,就沒法使用這個類(因此其餘類沒法使用【局部內部類】)
普及:
權限修飾符的使用規則:
public > protected > (default) > private
1.外部類:能使用 public / (defautl) 修飾
2.成員內部類: public / protected / (default) / private
3.局部內部類:什麼都不寫
public class Test {
public void fun(){
final int num = 100;
class Fun{
private void fun2(){
System.out.println(num);
}
}
Fun fun = new Fun();
fun.fun2();
}
}
複製代碼
問題:爲何訪問所在方法的局部變量,必需要有final修飾?
緣由(本質是生命週期問題):
1.內部類 new 出來的對象在堆內存中;
2.局部變量跟着方法,在棧內存中;
3.方法運行完,馬上出棧,局部變量跟着消失;
4.但 new 出來的對象,會在堆內存持續存在,直到垃圾回收;
5.因此,要將該內存複製到常量池才能保存繼續使用。
往常,咱們要使用接口方法,得先定義該接口的實現類 -> 重寫該接口的全部抽象方法 -> new 實現類使用。
而若是接口的實現類只是用惟一的一次,那麼這種狀況就能夠省略該實現類的定義,而改成使用 【匿名內部類】
接口
public interface MyInteface {
void method();
}
複製代碼
使用【匿名內部類】
/** * 格式: * 接口名稱 對象名 = new 接口名稱(){ * // 覆蓋重寫全部抽象方法 * }; */
public class AnonymityTest2 {
public static void main(String[] args) {
MyInteface my = new MyInteface(){
@Override
public void method() {
System.out.println("匿名內部類方法");
}
};
my.method();
}
}
複製代碼
不少人一開始可能會有誤解:不是【匿名內部類】嗎? MyInteface my = new MyInteface(){...} 這不是有名字麼?
先看,對於"new MyInteface(){...};" 的解析:
1). new 表明對象建立的動做;
2). 接口名稱 【匿名內部類】要實現的接口;
3). {...} 這纔是【匿名內部類】的內容,裏面重寫着接口的全部抽象方法
它光禿禿的,的確沒名沒姓的。
而 MyInteface my = new MyInteface(){...} 中的 my 是對象名,它是供你調用匿名類方法的對象。
ps:匿名內部類、匿名對象
一、【匿名內部類】表示,在建立對象是,只能使用惟一一次,通常用於書寫接口的實現類。
若是但願屢次建立對象,並且類的內容同樣的話,那仍是單獨定義實現類更方便。
public class AnonymityTest2 {
public static void main(String[] args) {
MyInteface my1 = new MyInteface(){
@Override
public void method() {
System.out.println("匿名內部類方法");
}
};
my1.method();
MyInteface my2 = new MyInteface(){
@Override
public void method() {
System.out.println("匿名內部類方法");
}
};
my2.method();
}
}
複製代碼
2.【匿名對象】表示,在調用方法時,只能調用惟一一次。
若是但願同一對象,調用屢次方法,那麼仍是給對象起個名把。
new MyInteface(){
@Override
public void method1() {
System.out.println("匿名內部類方法1");
}
@Override
public void method2() {
System.out.println("匿名內部類方法2");
}
}.method1();
new MyInteface(){
@Override
public void method1() {
System.out.println("匿名內部類方法1");
}
@Override
public void method2() {
System.out.println("匿名內部類方法2");
}
}.method2();
複製代碼
3.二者不是一回事
【匿名內部類】是省略了 <實現類 / 子類>
【匿名對象】是省略了 <對象名稱>
二者不是一回事。
public class AnonymityTest {
public static void main(String[] args) {
fun1();
}
private static void fun1() {
// 對於 Thread 來講,這就是【匿名對象】
// 對於 Runnable 來講,這就是【匿名內部類】
new Thread( new Runnable(){
@Override
public void run() {
}
}).start();
}
}
複製代碼