文章目录
- 1.基本介绍
- 1.定义:
- 2.基本语法:
- 3.内部类的分类
- 2.局部内部类
- 1.快速入门
- 2.局部内部类的使用
- 3.匿名内部类
- 1.匿名内部类实现接口
- 2.匿名内部类继承抽象类
- 3.匿名内部类细节
- 4.匿名内部类最佳实践
- 1.匿名内部类作为实参传入函数
- 2.匿名内部类课堂练习
- 4.成员内部类
- 成员内部类的使用
- 5.静态内部类
- 静态内部类的使用
1.基本介绍
1.定义:
一个类的内部又完整的嵌套了另一个类结构,被嵌套的类称为内部类,嵌套其他类的类被称为外部类。
2.基本语法:
3.内部类的分类
- 定义在外部局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名)
- 定义在外部类的成员位置上
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
2.局部内部类
1.快速入门
package innerclass;
public class LocalInnerClass {
public static void main(String[] args) {
new Outer02().m1();
}
}
class Outer02 { //外部类
private int n1 = 100;
private void m2() { //私有方法
System.out.println("这是外部类的私有方法");
}
public void m1() {
class Inner02 { //局部内部类,是放在代码块或者方法中(本质仍然是一个类)
public void f1() {
System.out.println("外部类的私有属性:" + n1); //局部内部类可以直接访问外部类的所有私有成员
}
}
class Inner03 extends Inner02 { //局部内部类可以被继承
public void f2() {
super.f1(); //可以访问父类的方法
m2();//还可以访问外部类的私有方法
}
}
new Inner03().f2(); //在方法中创建局部内部类的对象然后调用方法
}
}
2.局部内部类的使用
-
局部内部类既是一个局部变量又是一个类
-
局部内部类可以访问外部类的所有成员,包括私有的
-
不能添加访问修饰符,因为他的地位是一个局部变量,但是可以使用final修饰
-
作用域:仅仅在定义他的方法或者代码块中
-
外部类访问局部内部类的方式,在方法或者代码块中声明局部内部类的对象然后调用
-
外部其他类不能访问局部内部类,因为局部内部类地位是一个局部变量
-
如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用
外部类名.this.成员
外部类名.this的意思是外部类的一个对象,就相当于普通类中的this,谁调用的这个方法,则这个对象就是谁
-
代码实例
package innerclass; public class LocalInnerClass { public static void main(String[] args) { new Outer02().m1(); } } class Outer02 { //外部类 private int n1 = 100; public void m1() { class Inner02 { //局部内部类,是放在代码块或者方法中(本质仍然是一个类) int n1 = 200; //与外部类中的属性重名,默认遵循就近原则 public void f1() { System.out.println("局部内部类中的n1 = " + n1); //根据就近原则,访问了局部内部类中的n1 System.out.println("外部类中的n1 = " + Outer02.this.n1); } } new Inner02().f1(); } }
3.匿名内部类
1.匿名内部类实现接口
-
需求:想使用一个接口,并创建对象,但是只使用一次
-
传统方式:写一个类,实现接口,并创建对象
-
可以使用匿名内部类来简化开发
-
jdk底层:创建了一个匿名内部类,实现了接口,然后返回一个这个匿名内部类的对象
-
代码实例
package innerclass; public class AnonymousInnerClass { public static void main(String[] args) { new Out().method(); } } interface IA { void cry(); } class Out { //外部类 public void method() { IA tiger = new IA() { //编译类型是IA , 运行类型是匿名内部类Out$1 @Override public void cry() { System.out.println("老虎在哭"); } }; //匿名内部类,底层进行了,写一个匿名内部类,实现了接口IA,然后返回了一个对象 tiger.cry(); System.out.println("匿名内部类的名字:" + tiger.getClass()); } }
2.匿名内部类继承抽象类
-
匿名内部类可以继承普通类或者抽象类
-
jdk底层:创建一个匿名内部类,继承了抽象类,重写抽象类的抽象方法,返回一个匿名内部类的对象,如果有构造器相当于调用了父类的构造器
-
代码实例
package innerclass; public class AnonymousInnerClass { public static void main(String[] args) { new Out().method(); } } abstract class Father1 { public Father1(String name) { } public abstract void cry(); //抽象方法 } class Out { //外部类 public void method() { Father1 father = new Father1("父亲") { //匿名内部类整个过程相当于,1.创建一个匿名内部类 2.继承了Father类 3.返回一个匿名内部类的对象 //这个匿名内部类继承了抽象类则需要重写抽象方法 @Override public void cry() { System.out.println("匿名内部类重写了父类的抽象方法"); } }; father.cry(); } }
3.匿名内部类细节
-
匿名内部类是以一个类似于类的形式展示,但是其实他是这个类返回的一个对象,所以可以直接使用这个匿名内部类对象来访问里面的成员
-
匿名内部类可以直接访问外部类的所有成员,包括私有的
-
不能给匿名内部类直接添加访问修饰符,因为匿名内部类本身也是一个局部变量
-
匿名内部类的作用域:仅仅在定义它的方法或代码块中
-
匿名内部类访问外部类的成员的方式是直接访问
-
如果内部类的属性跟外部类的属性冲突,则可以使用类名.this.属性名的方式访问外部类的属性
-
其他外部类不能访问匿名内部类,因为匿名内部类只是一个局部变量
-
代码实例
package innerclass; public class AnonymousInnerClassDetail { public static void main(String[] args) { new Outer05().f1(); } } class Person { public void hi(String name) { System.out.println("你好:" + name); } } class Outer05 { private int n1 = 99; public void f1() { new Person() { //匿名内部类继承了Person类 @Override public void hi(String name) { //重写了hi方法 super.hi(name); } }.hi("小明");//这相当于匿名内部类的一个对象可以直接调用方法 new Person() { int n1 = 100; //这里的属性跟外部类的属性重名了 public void printn1() { System.out.println("外部类的n1:" + Outer05.this.n1); //使用外部类名.this.属性名来访问与内部类重名的外部属性 System.out.println("内部类的n1:" + n1); } }.printn1(); } }
4.匿名内部类最佳实践
1.匿名内部类作为实参传入函数
package innerclass;
public class InnerclassExercise01 {
public static void main(String[] args) {
f1(new IL() {
@Override
public void show() {
System.out.println("我实现了接口的IL方法");
}
}); //使用匿名内部类直接作为实参传入函数
}
public static void f1(IL li) {
li.show();
}
}
interface IL {
void show();
}
2.匿名内部类课堂练习
-
代码
package innerclass; public class InnerclassExercise02 { public static void main(String[] args) { new CellPhone().alarmclock(new Bell() { @Override public void ring() { System.out.println("懒猪起床了"); } }); new CellPhone().alarmclock(new Bell() { @Override public void ring() { System.out.println("小伙伴上课了"); } }); } } interface Bell { void ring(); } class CellPhone { public void alarmclock(Bell bell) { bell.ring(); } }
-
结果
4.成员内部类
成员内部类的使用
-
说明:成员内部类是定义在外部类的成员位置,并且没有static修饰
-
可以直接访问外部类的所有成员,包括私有的
-
可以添加任何访问修饰符,因为他的定位就是一个成员
-
作用域:和外部类的其他成员一样
-
成员内部类访问外部类的成员可以直接访问,当成员内部类的成员跟外部类的成员重名的时候,使用外部类名.this.成员名来访问
-
外部类访问成员内部类,创建对象访问
-
代码实例
package innerclass; public class MemberInnerClass01 { public static void main(String[] args) { new Outer01().f1(); Outer01 outer01 = new Outer01(); } } class Outer01 { //外部类 private int n1 = 10; public String name = "张三"; public class Innter01 { //成员内部类 public String name = "李四"; //成员内部类的属性跟外部类重名 public void say() { System.out.println("Outer01的n1:" + n1 + " Outer01的name:" + Outer01.this.name); //成员内部类可以访问外部类的所有成员,当重名的时候需要使用外部类名.this.属性名来访问 } } public void f1() { //使用成员内部类 Innter01 innter01 = new Innter01(); //外部类访问成员内部类,创建对象访问 innter01.say(); } }
-
外部其他类访问成员内部类有两种方式
- 通过外部类的实例来访问并创建一个成员内部类的实例
- 在外部类中暴露一个方法返回成员内部类的实例
package innerclass; public class MemberInnerClass02 { public static void main(String[] args) { //外部其他类访问成员内部类的第一种方式,使用外部类的实例来访问内部类并创建对象 Outer06.Innter innter = new Outer06().new Innter(); innter.method(); //第二种方式,在外部类中写一个方法直接返回成员内部类的对象 Outer06.Innter innter1 = new Outer06().getInnter(); innter1.method(); } } class Outer06 { //外部类 public class Innter { //成员内部类 public void method() { System.out.println("我是成员内部类"); } } public Innter getInnter() { //向外暴露一个方法来获得成员内部类的对象 return new Innter(); } }
5.静态内部类
静态内部类的使用
-
说明:静态内部类是有static的在成员位置的内部类
-
可以直接访问外部类的所有静态成员,包括私有的,但是不能直接访问非静态成员
-
可以添加任何访问修饰符,因为他的地位是一个成员
-
作用域:同其他的成员
-
静态内部类访问外部类的静态成员可以直接访问,如果重名,则使用外部类名.成员名来访问(不加this的原因静态内部类只能访问静态成员,所以就没有加this的必要)
-
外部类访问静态内部类 创建对象再访问
-
外部其他类访问静态内部类有三种方式
package innerclass; public class StaticInnerClass01 { public static void main(String[] args) { //外部其他类访问静态内部类的第一种方式,创建对象访问 Outer07.Inner02 inner02 = new Outer07.Inner02(); //因为他是静态的所以是是属于类的可以直接用类名访问 inner02.say(); //外部其他类访问静态内部类的第二种方式,在外部类中暴露一个普通方法返回静态内部类的实例 Outer07.Inner02 inner021 = new Outer07().getInner02(); inner021.say(); //外部其他类访问静态内部类的第三种方式,在外部类中暴露一个静态方法返回静态内部类的实例 Outer07.Inner02 inner022 = Outer07.getInner02_(); inner022.say(); } } class Outer07 { //外部类 public static class Inner02 { public void say() { System.out.println("我是静态内部类"); } } public Inner02 getInner02() { //普通方法返回静态内部类实例 return new Inner02(); } public static Inner02 getInner02_() { //静态方法返回静态内部类实例 return new Inner02(); } }
-
练习