一、什么是内部类
- 可以将一个类的定义放在另一个类的内部,这就是
内部类
。我们一般将内部类分为四种:成员内部类
、静态内部类
、局部(方法内部类)
、匿名内部类
。 外部类
的定义是相对于内部类
而言的。/** * 外部类 */ public class Outer { //... /** * 内部类 */ class Inner { //... } }
二、内部类
1.成员内部类
总结:【抓住关键字——实例,作为实例成员存在】
- 内部类可以是任何的访问修饰符。
由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰符。- 内部类的内部不能有静态信息。
- 内部类也是类,该继承的继承、该重写的重写、该重载的重载,this和super随便用。
外部类访问内部类的信息,必须先实例化内部类,然后 . 访问。
- 内部类可以直接使用外部类的任何信息,如果属性或者方法发生冲突(重名),使用
Outer.this.成员
- 其他类访问内部类:
成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在外部类的对象。
其他类访问内部类的方式
public class Test {
public static void main(String[] args) {
//第一种方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner(); //必须通过Outter对象来创建
//第二种方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
/**
* 成员内部类
*/
class Inner {
public Inner() {
}
}
}
2.静态内部类
/**
* 外部类、内部类定义
*/
public class Outer {
private int outerVariable = 1;
/**
* 外部类定义的属性(重名)
*/
private static int commonVariable = 2;
private static int outerStaticVariable = 3;
static {
System.out.println("② Outer的静态块被执行了……");
}
/**
* 成员方法
*/
public void outerMothod() {
System.out.println("我是外部类的outerMethod方法");
}
/**
* 静态方法
*/
public static void outerStaticMethod() {
System.out.println("③ 我是外部类的outerStaticMethod静态方法");
}
/**
* 静态内部类
*/
public static class Inner {
/**
* 成员变量
*/
private int innerVariable = 10;
private static int commonVariable = 20;
private static int innerStaticVariable = 30;
static {
System.out.println("① Outer.Inner的静态块执行了……");
}
/**
* 成员方法
*/
public void innerShow() {
System.out.println("innerVariable:" + innerVariable);
System.out.println("外部的commonVariable:" + commonVariable);
System.out.println("内部的commonVariable:" + Outer.commonVariable);
outerStaticMethod();
}
/**
* 静态方法
*/
public static void innerStaticShow() {
//调用时会先加载Outer类,类加载的时候执行静态代码块
outerStaticMethod();
//访问外部类的属性,不重名直接访问
System.out.println("④ outerStaticVariable" + outerStaticVariable);
}
}
/**
* 外部类的内部如何和内部类打交道
*/
public static void callInner() {
System.out.println(Inner.innerStaticVariable);
Inner.innerStaticShow();
}
}
/**
* 其他类访问静态内部类
*/
class Other {
public static void main(String[] args) {
//访问静态内部类的静态方法,Inner类被加载(类加载的时候执行静态代码块),此时外部类未被加载,独立存在,不依赖于外部类。
Outer.Inner.innerStaticShow();
//访问静态内部类的成员方法
Outer.Inner oi = new Outer.Inner();
oi.innerShow();
}
}
总结:【抓住关键字——static,作为静态成员存在】
- 静态内部类可以包含任意的信息,可以被任意访问权限修饰符修饰。
- 静态内部类的方法只能访问外部类的static关联的成员。
- 静态内部类可以独立存在,不依赖于其他外围类。
- 其他类访问内部类的静态信息,直接
Outer.Inner.static成员信息
就可以了。- 其他类实例化内部类
Outer.Inner instance = new Outer.Inner();
,然后instance.
成员信息(属性、方法)即可。
3.局部内部类
总结:【抓住关键——作用域,作为方法的局部成员存在】
- 局部内部类不能有访问权限修饰符,无法创建静态信息。
局部内部类就像是方法里面的一个局部变量一样,是不能有访问权限修饰符和static修饰符的。
- 只能在方法内部使用。
- 可以直接访问方法内的局部变量和参数。【
存在限制,需要 final 或有效的final修饰的。
】,但是不能更改。
①直接被final修饰的变量。
②已被赋值且始终未改变的变量(有且仅有赋值一次),引用指向不能改变。JDK8以前(不包括8)只能访问被final修饰的变量。
4.匿名内部类
- 匿名内部类主要用于在我们需要的时候
创建一个对象
来执行特定的任务,可以使代码更加简洁。- 原本我们需要创建子类或实现类,去继承父类或实现接口,才能重写其中的方法。但是有时候我们这样做了,然而子类和实现类却只使用了一次(定义了一个对象)。这个时候我们就可以使用匿名内部类,不用去写子类和实现类,起到简化代码的作用。
- 这样做,
把子类继承父类,重写父类中的方法,创建子类对象,合成了一步完成,减少了其中创建子类的过程。
或者实现类实现接口,重写接口中的方法,创建实现类对象,合成了一步完成,减少了其中创建实现类的过程。
- 匿名内部类是不能有名字的类,他们
不能被引用
,只能在创建是用new
语句来声明他们。 - 语法格式:
匿名类继承父类
public class Anonymous_inner_class {
public static void main(String[] args) {
person p = new person(){
@Override
public void method() {
System.out.println("重写父类方法");
}
};
p.method();
}
}
class person{
public void method(){
System.out.println("父类方法");
}
}
匿名类实现接口
// 自定义的接口
interface Product {
double getPrice();
String getName();
}
//外部类
public class Outer {
public void test(Product p) {
System.out.println(p.getName() + "-------->" + p.getPrice());
}
public static void main(String[] args) {
Outer as = new Outer();
//创建匿名内部类,实现接口并实现抽象方法
as.test(new Product() {
@Override
public double getPrice() {
return 9999.99;
}
@Override
public String getName() {
return "iPhone 15 pro";
}
//这里虽然你增加了自己定义的方法,但是内部类是父类指向子类型的,所以在test方法中也无法调用。
public Date getDate(){
return new Date();
}
});
}
}
总结:【匿名内部类通常继承一个类或实现一个接口】
- 匿名内部类没有访问权限修饰符。
- 匿名内部类要实现父类或接口的所有抽象方法,其他方法可以根据自己的情况进行重写。
- 匿名内部类不应当添加自己的成员,因为匿名类没有类名无法向下转型,父类型的引用无法访问。
匿名内部类访问方法参数时也有和局部内部类同样的限制。
- 匿名内部类没有构造方法。
- 匿名类是
表达式形式定义
的,所以末尾以分号;
来结束。
三、参考
[1]. 详谈Java内部类(超详细代码示例)
[2] Java 匿名类
[3] Java 内部类详解