整理
什么是内部类:在类里面重新定义一个类,如下
public class OuterClass {
private String name ;
class InnerClass{
public InnerClass(){
name = "chenssy";
}
}
}
内部类的作用
1.内部类可以很好的实现隐藏
一般的非内部类,是不允许有 private 与protected权限的,但内部类可以
2.内部类拥有外围类的所有元素的访问权限
3.可是实现多重继承
4.可以避免修改接口而实现同一个类中两种同名方法的调用。
举例说明如下:
1.实现隐藏
平时我们对类的访问权限,都是通过类前面的访问修饰符来限制的,一般的非内部类,是不允许有 private 与protected权限的,但内部类可以,所以我们能通过内部类来把我们的信息对同一包中的其他类隐藏起来。可以看下面的例子:
接口
public interface InnerInterface {
void innerMethod();
}
具体类
/** * 实现信息隐藏 */
public class OuterClass {
/** * private修饰内部类,实现信息隐藏 */
private class InnerClass implements InnerInterface {
@Override
public void innerMethod() {
System.out.println("实现内部类隐藏");
}
}
public InnerInterface getInner() {
return new InnerClass();
}
}
调用程序
public class Test {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
InnerInterface inner = outerClass.getInner();
inner.innerMethod();
}
}
打印
实现内部类隐藏
从这段代码里面我只知道OuterClass的getInner()方法能返回一个InnerInterface接口实例但我并不知道这个实例是这么实现的。而且由于InnerClass是private的,所以我们如果不看代码的话根本看不到这个具体类的名字,所以说它可以很好的实现隐藏。
2.可以无条件地访问外围类的所有元素
为什么可以引用:
内部类虽然和外部类写在同一个文件中, 但是编译完成后, 还是生成各自的class文件,内部类通过this访问外部类的成员。
1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象(this)的引用;
2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为内部类中添加的成员变量赋值;
3在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。
参考:https://blog.csdn.net/zhangjg_blog/article/details/20000769
编译指令 javac classpath(.java文件的路径)
反编译指令 javap -v(详细信息) classpath(.class文件的路径)
/** * 内部类无条件访问外部类元素 */
public class DataOuterClass {
private String data = "外部类数据";
private class InnerClass {
public InnerClass() {
System.out.println(data);
}
}
public void getInner() {
new InnerClass();
}
public static void main(String[] args) {
DataOuterClass outerClass = new DataOuterClass();
outerClass.getInner();
}
}
打印
外部类数据
data这是在DataOuterClass定义的私有变量。这个变量在内部类中可以无条件地访问.
3.可以实现多重继承
我们知道 java 是不允许使用 extends 去继承多个类的。内部类的引入可以很好的解决这个事情。
以下引用 《Thinking In Java》中的一段话:
每个内部类都可以队里的继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类没有影响
如果没有内部类提供的、可以继承多个具体的或抽象的类的能力,一些设计与编程问题就难以解决。
接口解决了部分问题,一个类可以实现多个接口,内部类允许继承多个非接口类型(类或抽象类)。
我的理解 Java只能继承一个类这个学过基本语法的人都知道,而在有内部类之前它的多重继承方式是用接口来实现的。但使用接口有时候有很多不方便的地方。比如我们实现一个接口就必须实现它里面的所有方法。而有了内部类就不一样了。它可以使我们的类继承多个具体类或抽象类。如下面这个例子:
类一
public class ExampleOne {
public String name() {
return "inner";
}
}
类二
public class ExampleTwo {
public int age() {
return 25;
}
}
类三
public class MainExample {
/** * 内部类1继承ExampleOne */
private class InnerOne extends ExampleOne {
public String name() {
return super.name();
}
}
/** * 内部类2继承ExampleTwo */
private class InnerTwo extends ExampleTwo {
public int age() {
return super.age();
}
}
public String name() {
return new InnerOne().name();
}
public int age() {
return new InnerTwo().age();
}
public static void main(String[] args) {
MainExample mi = new MainExample();
System.out.println("姓名:" + mi.name());
System.out.println("年龄:" + mi.age());
}
}
大家注意看类三,里面分别实现了两个内部类 InnerOne,和InnerTwo ,InnerOne类又继承了ExampleOne,InnerTwo继承了ExampleTwo,这样我们的类三MainExample就拥有了ExampleOne和ExampleTwo的方法和属性,也就间接地实现了多继承。
4.避免修改接口而实现同一个类中两种同名方法的调用。
大家假想一下如果,你的类要继承一个类,还要实现一个接口,可是你发觉你继承的类和接口里面有两个同名的方法怎么办?你怎么区分它们??这就需要我们的内部类了。看下面的代码
接口
public interface Incrementable{
void increment();
}
类 Increment
public class Increment {
public void increase() {
System.out.println("Increment increase()");
}
static void f(Increment f) {
f.increase();
}
}
此时接口和类中有相同的方法increase()。当不用内部类直接实现这两个类时
public class IncreaseNoInner extends Increment implements Incrementable {
public void increase() {
//代码
}
}
此时increase()方法存在歧义,是属于覆盖Increment这里的方法呢?还是Incrementable这里的方法。我怎么能调到Increment这里的方法?显然这是不好区分的。而我们如果用内部类就很好解决这一问题了。看下面代码
public class IncreaseWithInner extends Increment{
private int i = 0;
private void incr() {
i++;
System.out.println(i);
}
private class Closure implements Incrementable {
@Override
public void increase() {
incr();
}
}
Incrementable getCallbackReference() {
return new Closure();
}
public static void main(String[] args) {
IncreaseWithInner increase=new IncreaseWithInner();
increase.increase();
increase.getCallbackReference().increase();
}
}
我们可以用内部类来实现接口,这样就不会与外围类的方法冲突了。