首先我们先看看接口的定义:
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口是抽象类型,不能被实例化,也就是说不能通过new一个实例,但是确实有new的情况,例如:
import org.junit.Test;
public class Test2 {
@Test
public void test() {
Runnable run = new Runnable(){
@Override
public void run() {
System.out.println("新线程开始");
System.out.println(this.getClass().getName());
}
};
new Thread(run).start();
}
}
这是怎么回事呢?原来是编译器的优化,编译器创建了一个实现类,可以在bin目录下看到多了一个文件Test2$1.class:
反编译一下:
import java.io.PrintStream;
class Test2$1
implements Runnable
{
Test2$1(Test2 paramTest2)
{
}
public void run()
{
System.out.println("新线程开始");
System.out.println(getClass().getName());
}
}
我们看看输出:
所以接口new的结果最终还是生成类的实例,只不过这个类我们看不到,是一个匿名内部类。
内部类总结
Java编程思想第十章专门介绍了内部类,内部类确实神奇而且复杂。但是内部类在编程中被应用的场景很少,这主要是看设计者的设计思想,不过它的语法和特性却有很多。对于内部类来说要记住可以继承内部类但是不能覆盖。
普通内部类:
普通的内部类,就是在class里面普通的定义一个类:
package com.inspur.innerClass;
public class OuterClass {
public class InnerClass{
}
}
普通内部类,或者说平凡的内部类,有如下特性:(总结自《Java编程思想》)
(1)这个类在外部类的外面不能被直接访问,需要通过OuterClassName.InnerClassName方式访问。比如Map的Map.Entry就是一个内部接口,只能通过Map.Entry方式来使用它。
(2)内部类对象在创建后会秘密的链接到外部类对象上,隐含的有一个指向外部类对象的引用,所以没有外部类对象,是无法实例化内部类对象的。也就是我们无法独立于外部类创建一个内部类对象。(这里不包括声明为static的内部类,那不是平凡的内部类)
(3)因为内部类隐含的有一个指向外部类的指针,所以内部类可以访问外围类的成员,而且是外围类的所有成员,包括private的成员。
(4)在内部类中使用OuterClassName.this可以访问外围类对象。
(4)如果想要在外部类外面实例化内部类对象,那么可以同.new语法,也就是outerObject.new InnerClass()的方式:
import org.junit.Test;
public class OuterClass {
public void outerShow(){
System.out.println("外部类输出");
}
public class InnerClass{
public void innerShow(){
System.out.println("内部类输出");
}
}
@Test
public void test(){
OuterClass out = new OuterClass();
out.outerShow();
OuterClass.InnerClass inner = out.new InnerClass();
inner.innerShow();
}
}
(5)内部类最大的用途是:它可以实现接口或者继承某个类,这样使用内部类时,用基类引用内部类对象,可以屏蔽内部类的细节。这样的好处是,可以实现伪“多重继承”等。
(6)普通的内部类不能有static字段和static数据,也不能包含嵌套类。
在方法和作用域内的内部类:
如果内部类出现在了方法和作用域内,那么它就不是“平凡”的内部类了,而且这个内部类的作用域就是在这个方法的作用域内,方法外面是无法访问到的!但是它仍然具有“平凡”的内部类特性。
匿名内部类:
匿名内部类,在内部类的基础上减少了对class的定义,直接用new 后面跟一个接口或者基类,然后类体里面实现方法即可,这样JVM会调用编译器生成的构造器来生成这个内部类对象,并且编译器帮忙生成这个内部类的类结构。匿名内部类好处是语法简单,但是不方便阅读,在Android编程中,对Button的监听经常会用匿名内部类。匿名内部类有一些限制:匿名内部既可以扩展类,也可以实现接口,但是不能两者兼备,而且只能实现一个接口。
嵌套类:
嵌套类就是在内部类的基础上加上static声明,也就是静态的内部类。嵌套类跟普通的内部类特性有很大不同,特点:
(1)在构造时,不需要外围类的对象,但是同样,它只能访问外围类中的static字段;
(2)嵌套类可以有static数据和字段;
(3)嵌套类可以作为接口的一部分,这样在接口中就可以用公用代码出现;
(4)嵌套类是可以多重嵌套的,嵌套多少层不重要,它都可以访问它所有外围类成员。
内部类标识符:
部类必须生成一个class文件以包含它的Class对象信息,这些类文件有严格的命名规则:外围类的名字,加上“$”,再加上内部类的名字。