最近在学Java,在研究内部类的时候,发现有的文章或者视频没有很好的说出内部类之间的区别,所以下面内容我结合了我从哔哩哔哩看到的内容,来说说内部类(如果有不对的地方请留言评论)
内部类的分类
1、定义在外部局部位置上:局部内部类(有类名)、匿名内部类(没有类名)
2、定义在外部类的成员位置上:成员内部类(没有static修饰)、静态内部类(没有static修饰)
例如:
/*
内部类演示
*/
package innerclass;
//外部其他类
public class innerClass {
public static void main(String[] args) {
}
}
//外部类
class Outer{
// 内部类
class Inner{
}
}
一、局部内部类
1、局部内部类是定义在外部类的局部位置,通常在方法
2、可以直接访问外部类的所有成员,包含私有的
3、不能添加访问修饰符,但是可以使用final修饰
4、作用域:仅仅在定义它的方法或代码块
5、局部类可以直接访问外部的成员
6、如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类成员,使用“外部类名.this”
例如
package innerclass;
/*
演示局部内部类
*/
//外部其他类
public class LocalInnerClass {
public static void main(String[] args) {
Outer outer=new Outer();
outer.m2();
}
}
//外部类
class Outer{
private int n1=100;
private void m1(){
System.out.println("Outer");
}
public void m2(){
//局部内部类
class Inner02{
private int n1=800;
public void f1(){
// Outer02.this本质就是外部类的对象,即哪个对象调用了m1,Outer02.this就是哪个对象
// 打印局部内部类Inner02的n1变量和外部类Outer的n1变量
System.out.println("n1="+n1+" 外部类的 n1="+Outer.this.n1);
// 调用外部类Outer的私有方法m1
m1();
}
}
// 定义一个Inner03类,继承自Inner02类
class Inner03 extends Inner02{
}
// 创建Inner02类的一个实例对象inner02
// 调用inner02实例的f1方法
Inner02 inner02=new Inner02();
inner02.f1();
}
}
输出结果
n1=800 外部类的 n1=100
Outer02
二、匿名内部类
1、基于类的匿名内部类
- father的编译类型Father
- father的运行类型Outer04$2,同时返回类匿名内部类Outer04$2的对象
底层实现:
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
}
2、基于接口的匿名内部类
- 需求:想使用IA接口,并创建对象
- 传统方式,是写一个类,实现该接口,并创建对象
- 现在需求是Tiger就用一次,后面不再使用
- 可以使用匿名内部类简化开发
- tiger的编译类型是“IA”
- tiger的运行类型是匿名内部类:XXXX名字是存在的,为: “Outer04$1”
- JDK底层在创建匿名内部类 Outer04,立即马上创建类Outer04$1实例,并把地址返回给tiger
- 匿名内部类使用一次就不能再使用类,但是实例化的对象没关系
底层实现:
class Outer04$1 implements IA{
@Override
public void cry() {
System.out.println("老虎叫~~~");
}
例如
/*
演示匿名内部类
*/
package innerclass;
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04=new Outer04();
outer04.method();
}
}
//外部类
class Outer04{
private int n1=10;
public void method(){
// IA tiger=new Tiger();
// tiger.cry();
// 基于接口的匿名内部类
IA tiger =new IA() {
@Override
public void cry() {
System.out.println("老虎叫~~~");
}
};
System.out.println("tiger的运行类型="+tiger.getClass());
tiger.cry();
//基于类的匿名内部类
Father father =new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
father.test();
System.out.println("father对象的运行类型="+father.getClass());
//基于抽象类的匿名内部类
Animal animal=new Animal() {
@Override
void eat() {
System.out.println("小狗吃骨头");
}
};
animal.eat();
}
}
interface IA{
public void cry();
}
//传统对接口的重写方式
//class Tiger implements IA{
// @Override
// public void cry() {
// System.out.println("老虎叫~~~");
// }
//}
class Father{
//构造器
public Father(String name){
System.out.println("name:"+name);
}
public void test(){
}
}
//抽象类
abstract class Animal{
abstract void eat();
}
输出结果
tiger的运行类型=class innerclass.Outer04$1
老虎叫~~~
name:jack
匿名内部类重写了test方法
father对象的运行类型=class innerclass.Outer04$2
小狗吃骨头
三、成员内部类
- 注意:成员内部类,是定义在外部内的成员位置上
- 可以直接访问外部类的所有成员,包括私有的
- 可以添加任意访问修饰符(public、protected、默认、private),因为它的本身就是一个成员
- 如果成员内部类的成员和外部类的成员重名,会遵守就近原则
- 可以通过,外部类.this.属性 来访问外部类的成员
- 外部其他类,使用成员内部类的2种方式,1、第一种方式:outer08.new Inner08(); 相当于把 new Inner08()当作是Outer08一个成员;2、第二种方式:在外部类中,编写一个方法,可以返回Inner08对象
例如
package innerclass;
public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08=new Outer08();
outer08.t1();
System.out.println();
//外部其他类,使用成员内部类的2种方式
//第一种方式
//outer08.new Inner08(); 相当于把 new Inner08()当作是Outer08一个成员
//这就是一个语法
Outer08.Inner08 in08=outer08.new Inner08();
in08.say();
System.out.println();
//第二种方式
//在外部类中,编写一个方法,可以返回Inner08对象
Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
inner08Instance.say();
}
}
class Outer08{
private int n1=10;
public String name="李四";
private void hi(){
System.out.println("hi()方法~~~");
}
//成员内部类
class Inner08{
private double num=10.1;
private int n1=66;
public void say(){
System.out.println("内部 的n1="+n1+" Outer08 的name="+name+" 外部 的n1="+Outer08.this.n1);
hi();
}
}
public Inner08 getInner08Instance(){
return new Inner08();
}
public void t1(){
//使用成员内部类
//创建成员内部类的对象,然后调用的方法
Inner08 inner08=new Inner08();
inner08.say();
System.out.println("inner08: num="+inner08.num);
}
}
输出结果
内部 的n1=66 Outer08 的name=李四 外部 的n1=10
hi()方法~~~
inner08: num=10.1
内部 的n1=66 Outer08 的name=李四 外部 的n1=10
hi()方法~~~
内部 的n1=66 Outer08 的name=李四 外部 的n1=10
hi()方法~~~
四、静态内部类
- 放在外部类的成员位置
- 使用static修饰
- 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问- 非可以直接添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员
- 作用域:同其他的成员,整个类体
- 如果外部类和静态内部类的成员重名时,静态内部类访问默认,遵循就近原则,如果想访问外部类的成员,则可以使用(外部类.成员)
- 外部其他类访问静态内部类的方式。方式一:因为静态内部类是可以通过类名直接访问(前提是满足访问权限);方式二:编写一个方法可以返回静态内部类的对象示例
例如
package innerclass;
public class StaticInnerClass01 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他类访问静态内部类的方式
//方式一:
//因为静态内部类是可以通过类名直接访问(前提是满足访问权限)
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
//方式二
//编写一个方法可以返回静态内部类的对象示例
Outer10.Inner10 inner101=outer10.getinner10();
inner101.say();
Outer10.Inner10 inner102=outer10.getinner101();
inner102.say();
}
}
//外部类
class Outer10{
private int n1=10;
private static String name="Tom";
// 静态内部类
static class Inner10{
private static String name="Jack";
public void say(){
System.out.println("内部 name:"+name+" 外部 name:"+Outer10.name);
}
}
//外部类访问静态内部类方式:创建对象,再访问
public void m1(){
Inner10 inner10 =new Inner10();
inner10.say();
}
public Inner10 getinner10(){
return new Inner10();
}
public static Inner10 getinner101(){
return new Inner10();
}
}
输出结果
内部 name:Jack 外部 name:Tom
内部 name:Jack 外部 name:Tom
内部 name:Jack 外部 name:Tom
内部 name:Jack 外部 name:Tom