很多时候,类被定义成为一个独立的程序单元。但是在一些情况下,也会把一个类放在另一个类的内部进行定义,这个定义在其他类内部的类被称为内部类。
- 内部类成员可以直接访问外部类的私有数据,因为内部类被当成外部成员,同一个类的成员之间可以相互访问,但外部类不能访问内部类的实现细节。
- 静态成员不能访问非静态成员。
非静态内部类
定义: 把一个类放在另一个类的内部,未使用static修饰。
访问方式: 外部类实例.new 内部类。
当非静态内部类的方法访问某一个变量时,系统优先在该方法内查找是否有该名字的局部变量,如果存在就使用该变量;如果不存在,则到该方法所在的内部类中进行查找,如果存在则使用该成员变量;如果不存在,则到改内部类所在的外部类中进行查找,如果存在则使用该成员变量;如果依然不存在,则系统出现编译错误:提示找不到该变量。
- 如果外部类成员变量、内部类成员变量与内部类方法中的局部变量同名,则可以通过this、外部类类名.this作为限定来区分。
- Java不允许在非静态内部类里定义静态成员。
- 非静态内部类里不能有静态方法、静态成员变量、静态初始化块。
- 非静态内部类的构造器只能通过外部类来调用。
非静态内部类示例:
@Data
public class OuterClass {
private String name;
private Integer age;
public void outPrintf(){
System.out.println("this is out class ......");
}
@Data
private class InnerClass{
private String innerName;
private Integer age;
public void innerPrintf(){
int age = 12;
System.out.println("this is inner class ......");
System.out.println("out name = " + name);
System.out.println("innerName = " + innerName);
// 获取外部类同名成员变量
System.out.println("OuterClass.age = " + OuterClass.this.age);
// 获取内部类同名成员变量
System.out.println("InnerClass.age = " + this.age);
// 此处为局部变量age
System.out.println("age = " + age);
}
}
public static void main(String[] args) {
// 创建外部类实例
OuterClass outerClass = new OuterClass();
outerClass.setAge(22);
// 调用外部类方法
outerClass.outPrintf();
outerClass.setName("outName");
// 创建内部类实例
InnerClass innerClass = outerClass.new InnerClass();
innerClass.setInnerName("innerName");
innerClass.setAge(10);
// 调用内部类方法
innerClass.innerPrintf();
}
}
静态内部类
定义: 如果使用static
修饰一个内部类,那么这个内部类就属于外部类本身,而不属于外部类的某个对象。因此使用static修饰的内部类被称为类内部类,也称为静态内部类。
访问方式: 外部类示例.静态内部类
。获取静态内部类的静态成员变量可以使用内部类.静态成员变量
。
静态内部类可以包含静态成员,也可以包含非静态成员。静态内部类是外部类的一个静态成员,因此外部类的所有犯法、所有初始化块中可以使用静态内部类来定义变量、创建对象等。
根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的非静态成员,只能访问外部类的静态成员。即使是静态内部类的实例方法也不能访问外部类的实例成员,只能为访问外部类的静态成员。
静态内部类示例:
@Data
public class OuterClass {
private static String brand = "outBrand";
private String name;
private Integer age;
public void outPrintf(){
System.out.println("this is out class ......");
}
@Data
static class InnerClass{
private static String brand = "innerBrand";
private String innerName;
private Integer age;
public void innerPrintf(){
System.out.println("this is inner class ......");
// 获取外部类同名静态变量
System.out.println("out brand = " + OuterClass.brand);
// 获取内部类同名静态变量
System.out.println("InnerClass.age = " + brand);
}
}
public static void main(String[] args) {
// 创建外部类实例
OuterClass outerClass = new OuterClass();
outerClass.setAge(22);
// 调用外部类方法
outerClass.outPrintf();
outerClass.setName("outName");
// 创建内部类实例
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
// 通过类名获取内部类静态成员变量
String brand = InnerClass.brand;
System.out.println("inner brand = " + brand);
// 调用内部类方法
innerClass.innerPrintf();
}
}
局部内部类
定义: 如果把一个类放在方法里定义,则这个类就是一个局部内部类,局部内部类仅在改方法里有效。局部内部类不能使用访问修饰符和static修饰符修饰。
访问方式: 创建局部内部类对象(方法中)。
局部内部类示例:
@Data
public class OuterClass {
private static String brand = "outBrand";
private String name;
private Integer age;
public void outPrint(){
System.out.println("this is outPrint ......");
@Data
class InnerClass{
private String innerName;
private Integer age;
}
InnerClass innerClass = new InnerClass();
innerClass.setAge(10);
innerClass.setInnerName("innerName");
System.out.println("innerClass = " + innerClass);
}
public static void main(String[] args) {
// 创建外部类实例
OuterClass outerClass = new OuterClass();
outerClass.setAge(22);
outerClass.outPrint();
}
}
匿名内部类
定义: 匿名内部类适合创建只需要使用一次的类,定义格式如下:
new 实现接口() | 父类构造器(实参列表)
{
// 匿名内部类实现部分
}
** 匿名内部类规则:**
(1)匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。
(2)匿名内部类不能定义构造器。由于匿名内部类没有类名,无法定义构造器,但是可以定义初始化块。
匿名内部类示例:
interface Product{
String getBrand();
String getProductName();
}
class AnonymousTest{
public void test(Product product){
System.out.println("brand = " + product.getBrand() + ",productName = " + product.getProductName());
}
public static void main(String[] args) {
AnonymousTest anonymousTest = new AnonymousTest();
anonymousTest.test(new Product() {
// 初始化块
{
System.out.println("this is ........");
}
@Override
public String getBrand() {
return "testBrand";
}
@Override
public String getProductName() {
return "testProductName";
}
});
}
}