在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。内部类也是Java类的五大成份之一; Java类的五大成份
.class
文件,但是前面冠以外部类的类名和$
符号。详细说明
InnerClass ic = new InnerClass(); // InnerClass为内部类的类名
Test.InnerClass ti = newTest().new InnerClass(); // Test.innerClass是内部类的完整类名
提示:内部类的很多访问规则可以参考变量和方法。另外使用内部类可以使程序结构变得紧凑,但是却在一定程度上破坏了Java面向对象的思想。
如一个事务内部还有一个独立的事务,内部的事务脱离外部的事务无法独立使用
如果按照定义的位置来分类,那么内部类分为以下四种
类定义在了成员位置 (类中方法外称为成员位置,有static修饰的内部类)
类定义在了成员位置 (类中方法外称为成员位置,无static修饰的内部类)
特点:
static
关键字修饰的内部类,属于外部类本身的外部类.内部类
案例代码
// 外部类
class Outer {
// 静态成员变量
private static String sc_name = "墨白科技有限公司";
// 内部类
public static class Inner {
//成员变量
private String name;
// 构造器
public Inner(String name) {
this.name = name;
}
public void showName() {
System.out.println(this.name);
// 静态内部类可以直接访问外部类静态成员变量
System.out.println(sc_name);
}
}
}
// Test方法
public class Demo3 {
public static void main(String[] args) {
// 创建内部类对象| 外部类.内部类 变量 = new 外部类.内部类构造器();
Outer.Inner inner = new Outer.Inner("墨白");
inner.showName();
}
}
实例内部类特点
static
修饰的内部类,属于外部类对象的案例代码
// 外部类
class Outer2 {
// 实例内部类,属于外部类对象的
public class Inner2 {
// 成员变量
private String name;
// 实例内部类不能定义静态成员
// private static String sc_name = "墨白科技有限公司"; // 报错
public Inner2(String name) {
this.name = name;
}
public void showName() {
System.out.println(this.name);
}
}
}
// Test方法
public class Demo4 {
public static void main(String[] args) {
// 宿主:外部类对象
Outer2.Inner2 inner2 = new Outer2().new Inner2("墨白");
inner2.showName();
}
}
特点:
案例代码
public class Test {
int a = 0;
int d = 0;
public void method() {
int b = 0;
final int c = 0;
final int d = 10;
// 局部内部类
class Inner {
a2 = a; // 访问外部类中的成员
// int b2 = b; // 编译出错
int c2 = c; // 访问方法中的成员
int d2 = d; // 访问方法中的成员
int d3 = Test.this.d; //访问外部类中的成员
}
Inner i = new Inner();
System.out.println(i.d2); // 输出10
System.out.printIn(i.d3); // 输出0
}
public static void main(String[] args) {
Test t = new Test();
t.method();
}
}
匿名内部类 :是内部类的简化写法。匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类,它的本质是一个
带具体实现的
父类或者父接口的
匿名的
子类对象。实际开发中,最常用到的内部类就是匿名内部类了。
在没有学习匿名内部类之前,我们需要使用接口时,需要进行以下步骤:
// 定义一个接口
interface Swim {
// 抽象方法
public void swimming();
}
// 1.定义接口的实现类
class Student implements Swim {
// 2.重写抽象方法
@Override
public void swimming() {
System.out.println("蛙泳");
}
}
public class Demo5 {
public static void main(String[] args) {
// 3.创建实现类对象
Student student = new Student();
// 4.使用对象调用方法
student.swimming();
}
}
可以看到实现的过程很麻烦,而我最终的目的不过是想调用
swimming
方法而已,所以下面可以使用匿名内部类来简化开发
匿名内部类格式
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
interface Swim {
public abstract void swimming();
}
public class Demo07 {
public static void main(String[] args) {
// 使用匿名内部类
new Swim() {
@Override
public void swimming() {
System.out.println("自由泳...");
}
}.swimming();
// 接口 变量 = new 实现类(); // 多态,走子类的重写方法
Swim s2 = new Swim() {
@Override
public void swimming() {
System.out.println("蛙泳...");
}
};
s2.swimming();
s2.swimming();
}
}
通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:
interface Swim {
public abstract void swimming();
}
public class Demo07 {
public static void main(String[] args) {
// 普通方式传入对象
// 创建实现类对象
Student s = new Student();
goSwimming(s);
// 匿名内部类使用场景:作为方法参数传递
Swim s3 = new Swim() {
@Override
public void swimming() {
System.out.println("蝶泳...");
}
};
// 传入匿名内部类
goSwimming(s3);
// 完美方案: 一步到位
goSwimming(new Swim() {
public void swimming() {
System.out.println("大学生, 蛙泳...");
}
});
goSwimming(new Swim() {
public void swimming() {
System.out.println("小学生, 自由泳...");
}
});
}
// 定义一个方法,模拟请一些人去游泳
public static void goSwimming(Swim s) {
s.swimming();
}
}