1. 内部类
- 内部类就是在一个类中定义另一个类
- 分类
成员内部类
局部内部类(匿名内部类)
2. 成员内部类
- 格式:
修饰符 class 外部类名{
修饰符 class 内部类名{
}
}
//内部类使用外部类的内容,随便使用,不用管修饰符是啥,也不需要new
//外部类使用内部类的内容,需要通过new内部类的对象使用
-
外部类使用内部类
(1)间接使用:在外部类中使用内部类,main中只是调用外部类
即:在外部类的方法中中new一个内部类对象,使用这个内部类内容。而main中只需要new一个外部类的对象,然后调用这个方法即可间接使用内部类的内容
(2)直接使用:直接在main中创建对象
格式:外部类名.内部类名 对象名 = new 外部类名().new 内部类名()
-
内部类使用外部类
直接使用即可。
当变量名重复:外部类名称.this.变量名
-
示例:
package linxu.day09; public class Body { private int num = 10; public void mothodBody() { System.out.println("这是外部类"); } public void showheart() { heart he = new heart(); he.mothodheart();//外部使用内部,直接调用 } public class heart { private int num = 20; public void mothodheart() { System.out.println("这是内部类"); } public void shownum() { int num = 30; System.out.println("局部变量:" + num); System.out.println("内部类成员变量:" + this.num); System.out.println("外部类成员变量:" + Body.this.num);//内部使用外部 } } } package linxu.day09; public class demomain { public static void main(String[] args) { Body.heart obj = new Body().new heart(); obj.shownum(); obj.mothodheart();//直接调用内部类方法 Body obj2 = new Body(); obj2.showheart();//间接调用内部类方法 } } /*打印结果: 局部变量:30 内部类成员变量:20 外部类成员变量:10 这是内部类 这是内部类*/
-
文件结构:
$表示的就是内部类的意思
3. 局部内部类
一个定义在方法中的类。只能当前方法可以使用这个类。
package linxu.day09;
public class Outer {
public void mothod(){
class Inter{//局部内部类,不能加权限修饰符
public void mothodInter()
{
System.out.println("这是局部内部类的方法");
}
}
//Inter类只能在这个方法中使用,一旦到来方法外面,就失效了
//因此,只能在这个方法中调用,不能再main函数使用。
Inter in=new Inter();
in.mothodInter();
}
}
package linxu.day09;
public class demomain {
public static void main(String[] args) {
Outer ou=new Outer();
ou.mothod();//调用局部内部类的内容
}
}
4. 内部类的权限修饰符
外部类 | public/(default) |
成员内部类 | public/protected/(default)/private |
局部内部类 | 什么都不能写 |
5. 局部内部类的final
- 如果局部内部类想要访问所在方法体的局部变量,这个局部变量必须是final的。
即没有改变过的。如下图所示,一旦这个局部变量发生了改变,编译器就会报错。为了安全起见,最好将局部变量设置成final。(java8开始,只要局部变量事实上没有变,那么final可以省略)
- 原因:
new出来的对象是在堆内存
局部变量是在方法体,在栈中。
方法运行结束,立即出栈,局部变量会立刻消失。
但new的对象在堆内存持续存在,直到垃圾回收,因此对象会把局部变量的值复制一份到堆。
你一旦改变了局部变量的值,堆中复制的值不会随之改变,由此发生错误 - 示例:
package linxu.day09;
public class Outer {
public void mothod(){
final int num=10;
class Inter{//局部内部类,不能加权限修饰符
public void showNum(){
System.out.println(num);
}
}
Inter in=new Inter();
in.showNum();
}
}
package linxu.day09;
public class demomain {
public static void main(String[] args) {
Outer ou=new Outer();
ou.mothod();
}
}
6. 匿名内部类
- 如果接口的实现类(或父类的子类)只需要使用唯一一次,那么此时可以省略该类的定义,改为使用匿名内部类
- 格式:
接口名 对象名 =new 接口名(){//接口名可以是抽象的父类 //覆盖重写所有抽象方法 }; //接口名是匿名内部类实现的接口 //{...}中的是匿名内部类的内容
- 示例
package linxu.day10; public abstract class myinterface {//抽象类 public abstract void mothod();//抽象方法 } //这个抽象类没有子类,抽象方法也没有进行重写 package linxu.day10; public class maindemo { public static void main(String[] args) { myinterface obj = new myinterface(){//匿名内部类 @Override public void mothod() { System.out.println("匿名内部类重写抽象方法1"); } }; obj.mothod(); //匿名内部类的匿名对象 new myinterface(){//匿名内部类 @Override public void mothod() { System.out.println("匿名内部类的匿名对象重写抽象方法2"); } }.mothod(); } }
- 注意事项:
(1)匿名内部类,在创建对象时,只能使用唯一一次(再创建一个新对象,还需要在重新写一次匿名内部类)
(2)匿名对象,在调用方法时,只能调用唯一一次(想要调用第二次,必须重新创建一个匿名对象)
(3)匿名内部类是省略了实现类/子类的名称,匿名对象是省略了对象名