Tags : Java,Inner Class
1. 内部类的作用:
提供了更好的封装,可以把内部类隐藏在外部类里, 不允许同一个包的其他类访问该类。(==更清楚的组织逻辑==)
- 例如在GUI中, 如果我要给MyFrame里的一个Button添加一个监听器, 那么对于其他类(其他Frame)来说, 完全没有必要访问这个监听器类, 那么我便可以把这个监听器类设成这个Frame的内部类, 更严谨的来说, 可以设成
private class
, 从语法上就把它限制死了, 其他的类根本没有办法访问这个内部类。这时候疑问来了, 不设成内部类, 以后写代码的时候小心一点不访问不调用不就行了吗? 逻辑上是可以的,但是从设计本身来说, ==不该让别人访问的东西就不应该暴露出来==,这才是良好的设计习惯!
class MyFrame extends Frame { public void launchFrame() { Button b = new Button("ok"); b.addActionListener(new MyMonitor()); this.add(b); } // Inner class private class MyMonitor implements ActionListener { public void actionPerformed(ActionEvent e) { // ... } } }
- 例如在GUI中, 如果我要给MyFrame里的一个Button添加一个监听器, 那么对于其他类(其他Frame)来说, 完全没有必要访问这个监听器类, 那么我便可以把这个监听器类设成这个Frame的内部类, 更严谨的来说, 可以设成
可以方便的访问外部类的成员(属性、方法)
何时使用内部类?
该类不允许或者不需要其他类来访问它
2. 成员内部类
1. 非静态内部类
class Cow {
private double weight;
private String name;
public Cow(double weight, String name) {
this.weight = weight;
this.name = name;
}
public double getWeight() {
return this.weight;
}
public String getName() {
return this.name;
}
public void getCowLegColor() {
System.out.println(new CowLeg(15.00, "red").color);
}
/**
* Inner class
* @author EckoTan
* @version 1.0
*/
class CowLeg {
private double weight;
private String color;
public CowLeg() {
}
public CowLeg(double weight, String color) {
this.weight = weight;
this.color = color;
}
public double getWeight() {
return this.weight;
}
public String getColor() {
return this.color;
}
public void info() {
System.out.println("Name of the cow: " + name);
System.out.println("Weight of the cow:" + Cow.this.weight);
System.out.println("Weight of the cow's leg:" + this.weight);
}
}
}
public class TestInner {
public static void main(String[] args) {
Cow c = new Cow(100.00, "A");
Cow.CowLeg leg = c.new CowLeg(10.00, "white");
leg.info();
c.getCowLegColor();
}
}
非静态内部类可以方便的访问外部类的成员(属性、方法)
这是因为:==在非静态内部类对象里,保存了一个它寄存的外部类对象的引用==
- 当在非静态内部类的方法内访问某个变量时:
系统首先在方法内部查找是否存在该名字的局部变量, 若存在就使用该变量;
若方法不存在, 就去内部类中查找;
若内部类中不存在, 就会去外部类中查找;
若外部类中也没有, 报错。
例如: 内部类
CowLeg
中的info()
方法中访问name
,是访问外部类Cow
中的name
如果外部类属性、内部类属性与内部类方法里的局部变量同名, 可以通过this、 外部类类名.this区分
例如:
System.out.println("Weight of the cow:" + Cow.this.weight); System.out.println("Weight of the cow's leg:" + this.weight);
非静态内部类的成员可以访问外部类的private成员, 但反过来就不成立了。 非静态内部类的成员只在非静态内部类范围内是可知的, 并不能被外部类直接调用。如果外部类需要访问非静态内部类成员, 必须==显式创建非静态内部类对象调用、访问其实例成员==
例如:在
Cow
中的getCowLegColor()
方法想访问CowLeg
中的color
public void getCowLegColor() { System.out.println(new CowLeg(15.00, "red").color); }
- 当在非静态内部类的方法内访问某个变量时:
非静态内部类和外部类对象的关系
非静态内部类对象必须==寄存==在外部类对象里, 而外部类对象则==不必一定==有非静态内部类对象寄存在里面。 (有点类似寄生的关系, 内部类是寄生物, 外部类是宿主,寄生物必须在宿主里面存在, 因此有非静态内部类对象必然要由外部类对象, 但是宿主里面不必一定要有寄生物, 所以外部类对象里不一定有非静态内部类对象。)
根据静态成员不能访问非静态成员的规则, 外部类的静态方法、静态代码==不能访问非静态内部类==(包括不能使用非静态内部类定义的变量、 不能创建非静态内部类实例等)。 另外, Java**不允许**在非静态内部类里定义静态成员(==非静态内部类里不能有静态方法, 静态属性, 静态初始化块==)。
public class TestStatic { private class In { } // Static method of outer class public static void main(String[] args) { // Wrong! new In(); } }
2. 静态内部类
如果用static
来修饰一个内部类, 那么这个内部类就变成了是外部类类相关的, 属于整个外部类, 而不再是单独属于外部类的某个对象。
- 静态内部类可以包含静态成员, 也可以包含非静态成员。 根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员, 只能访问外部类的类成员(有
static
修饰的),即使是静态内部类的非static
方法也不能访问外部类的实例成员。(因为静态内部类是外部类的类相关, 而非外部类的对象相关。也就是说, 静态内部类的对象不是寄存在外部类的对象里, 而是寄存在外部类的类本身中。换而言之, 当静态内部类的对象存在时, 并不存在一个被它寄存的外部类对象。==静态内部类的对象里只有外部类的类引用,而没有外部类对象的引用。==)
public class TestStaticInnerClass {
private int num1 = 5;
private static int num2 = 0;
private static StaticInnerClass {
// Wrong!
System.out.println(num1);
// Correct!
System.out.println(num2);
}
}
静态内部类与外部类的关系
外部类依然不能直接访问静态内部类的成员, 但可以:
(1) 使用静态内部类的类名作为调用者来访问静态内部类的类成员(有static
修饰的)“`
内部类类名.类成员``
static`修饰的)
(2) 使用静态内部类的对象作为调用者来访问静态内部类的实例成员(无内部类对象.实例成员
例如:
public class Outer {
private static class StaticInnerClass {
private static int num1 = 5;
private int num2 = 6;
}
public void accessInner() {
// num1 is static.
System.out.println(StaticInnerClass.num1);
// num2 is not staitc.
System.out.println(new StaticInnerClass().num2);
}
}
3.使用内部类
在外部类内部使用内部类
与平常使用普通的类没有大的区别, 唯一需要注意的是:不要再外部类的静态成员(静态方法, 静态初始化块)中使用非静态内部类 (静态成员不能访问非静态成员)
在外部类以外使用非静态内部类
如果希望在外部类以外的地方访问内部类, ==则内部类的modifier不能使用private==, private修饰的内部类只能在其外部类里使用。
因为非静态内部类的对象必须寄存在外部类的对象里, 因此创建非静态内部类对象之前, ==必须先创建外部类对象(非静态内部类的构造方法必须通过其外部类对象来调用)==
syntax:
OuterInstance.new InnerConstructor()
例如:第一段代码中在
TestInner
这个类中创建leg
这个非静态内部类CowLeg
的对象Cow c = new Cow(100.00, "A"); Cow.CowLeg leg = c.new CowLeg(10.00, "white");
以上代码也可以写成:
Cow.CowLeg leg = new Cow(100.00, "A").new CowLeg(10.00, "white");
在外部类以外使用静态内部类
因为静态内部类是外部类类相关的, 所以创建静态内部类对象时无需创建外部类对象。
syntax:
new OuterClass.InnerConstructor();
例 :
class StaticOut { static class StaticIn { } } public class TestStatic { public static void main(String[] args) { StaticOut.StaticIn in = new StaticOut.StaticIn(); } }
==从以上代码可以看出:静态内部类和非静态内部类声明变量的语法完全相同, 唯一区别是在创建内部类对象时, 静态内部类只需使用外部类来调用构造方法, 非静态内部类必须使用外部类对象来调用构造方法。==
局部内部类
如果把一个内部类放在方法里面定义, 则这个内部类就是一个局部内部类, 仅仅在该方法内有效。
局部内部类不能使用访问控制符和static
修饰
例 :
public class TestLocalInner {
public static void main(String[] args) {
class LocalInner {
private int a;
}
LocalInner in = new LocalInner();
in.a = 6;
System.out.println("a = " + in.a);
}
}
匿名内部类
前面提到过, 在GUI中, 如果要给某一个Component或者给window添加一个监听器, 可以使用内部类。
例:
class MyFrame extends Frame {
public MyFrame(String name) {
super(name);
this.setBounds(300, 300, 400, 400);
this.setVisible(true);
this.addWindowListener(new MyMonitor());
}
class MyMonitor extends WindowAdapter {
public void windowClosing(WindowEvent e) {
setVisible(false);
System.exit(0);
}
}
}
上面的内部类也可以写成匿名类 :
class MyFrame extends Frame {
public MyFrame(String name) {
super(name);
this.setBounds(300, 300, 400, 400);
this.setVisible(true);
this.addWindowListener(new WindowAdapter {
public void windowClosing(WindowEvent e) {
setVisible(false);
System.exit(0);
}
});
}
}
上面这个匿名类本质的意义是 : 它从WindowAdapter继承, new了这个类的对象出来把它当成WindowAdapter传进addWindowListener这个方法里, 出了这个括号就再也没有人认识它了。
何时使用匿名内部类?
- 这个方法内逻辑比较简单, 语句比较少, 而且不需要经常变动
- 创建那些只需要一次使用的类
匿名内部类的规则:
- 不能是抽象类(因为创建匿名内部类的时候会立刻创建其对象, 而抽象类无法创建对象)
- 不能定义构造器, 因为它没有类名, 但可以定义实例初始化块, 通过初始化快来完成构造器需要完成的事情
如果匿名内部类需要访问外部类的局部变量, 必须使用
final
修饰符来修饰外部类的局部变量。
第一次写博客, 如有错漏, 请斧正!