我们把一个类放在另一个类的内部定义,称为内部类(inner class)。
内部类的两个要点:
- 内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
- 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。
注意
内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类。编译完成后会出现Outer.class和Outer$Inner.class两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。
代码中的内部类:
package TestInnerClass;
public class Outer {
String name;
int age = 80;
String major;
public void print(){
System.out.println(age);
System.out.println("外部类成员");
}
public Outer(String name, int age, String major) {
this.name = name;
this.age = age;
this.major = major;
}
public class innerClass{
int age;
String name;
public innerClass(int age, String name) {
this.age = age;
this.name = name;
}
public void inner(){
System.out.println("我是内部类成员!");
System.out.println("我是内部类的年龄:"+age);
System.out.println("我是外部类的年龄:"+Outer.this.age);
// 调用外部类的方法
Outer.this.print();
}
}
}
我们开始编写输出内容:
package TestInnerClass;
public class Test {
public static void main(String[] args) {
Outer o = new Outer("张三",18,"software"); //调用外部类成员
Outer.innerClass oi = new Outer().new innerClass(20,"李四"); //调用内部类成员
o.print();
System.out.println("===============");
oi.inner();
}
}
输出结果:
静态内部类
static class ClassName {
//类体
}
使用要点:
- 静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员。
- 静态内部类看做外部类的一个静态成员。
【示例】静态内部类的访问
代码实现:
package StaticInnerCLass;
public class StaticClass {
public static void main(String[] args) {
Outer.innerClass inner = new Outer.innerClass();
inner.print();
}
}
class Outer{
// private String a = "张三"; //错误:(17, 32) java: 无法从静态上下文中引用非静态 变量 a
private static String b = "李四";
static class innerClass{
public void print(){
// System.out.println(a);
System.out.println(b);
}
}
}
运行结果:
此类方法在我们开发过程中其实并不是很常见,但我们依然要了解其运行过程。
匿名内部类
适合那种只需要使用一次的类。比如:键盘监听操作等等。在安卓开发、awt、swing开发中常见。
在我们以前学习到的类和接口中的方法调用大致是这样的形式:
package AnonymousInnerClass;
//import TestInnerClass.Outer;
public class AnonmousOuter {
public void print(B b){
b.run();
}
public static void main(String[] args) {
AnonmousOuter ao = new AnonmousOuter();
ao.print(new A());
}
}
class A implements B{
@Override
public void run() {
System.out.println("我像飞一样自由!");
}
}
interface B{
public void run();
}
运行结果:
运行过程为我们主方法实例化了AnonmousOuter对象,又通过该对象调用了print方法,print方法中传递过来一个基于对象A实例化的参数,该参数值为描述了一个实现B接口的输出语句。
接下来我们实现我们的匿名内部类:
package AnonymousInnerClass;
//import TestInnerClass.Outer;
public class AnonmousOuter {
public void print(B b){
b.run();
}
public static void main(String[] args) {
AnonmousOuter ao = new AnonmousOuter();
// ao.print(new A());
ao.print(new A(){
@Override
public void run() {
// super.run();
System.out.println("我还是我,飞的很自由!");
}
});
ao.print(new A(){
public void run(){
System.out.println("第二层次匿名内部类!");
}
});
}
}
class A implements B{
@Override
public void run() {
System.out.println("我像飞一样自由!");
}
}
interface B{
public void run();
}
我们在对象调用方法的过程中对新的对象的方法进行了重写!