可以将一个类的定义放在另一个类的内部,这就是内部类。内部类的表面意义一目了然,不过内部类的实现语法还是稍显繁琐。
内部类的分类
:内部类主要分为:普通内部类,匿名内部类,局部内部类,嵌套内部类(静态内部类)。
普通内部类
普通内部类内不能有静态成员变量和静态方法
public class Outer{
class Inner{
private String name;
public Inner(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
public Inner getInner(String name){
return new Inner(name);
}
public static void main(String[] args){
Outer out = new Outer();
Inner inner = out.getInner("inner");
System.out.println(inner.getName());
}
}
普通内部类拥有对外部类的全部访问权,它能够与外部类进行通信并且可以操作外部类。当某个外部类对象创建了一个内部类对象,该内部类对象会秘密的保留一个指向创建它的外部类对象的引用。当内部类中访问外部类成员时,就是通过这个隐藏引用来拥有外部类的访问权。换句话说,内部类对象只能在与其外围类的对象关联的情况下才能创建(不包括静态内部类),构建内部类对象时,需要一个指向其外部类的引用,如果找不到这个引用,则编译器报错。
普通内部类不能含有静态成员变量和静态方法。
最典型的应用就是外部类有一个公共方法a,该方法返回一个内部类(该内部类是private的并且实现了某个公共接口,外部无法直接访问类,只能通过接口)对象的引用,也就是返回类型为公共接口类型
这样既可以得到一个公共接口的实现类,又完美隐藏了其实现细节,客户端不知道实现类的名字(因为该类是私有的,客户端无法访问),只能通过公共方法a得到它。java集合中的迭代器Iterator()就是其一。
例如:
//接口类
public interface Selector {
boolean end();
void next();
Object curr();
}
//主类
public class Outer_3 {
class SelectorImpl implements Selector {
@Override
public boolean end() {
return false;
}
@Override
public void next() {
}
@Override
public Object curr() {
return null;
}
}
public Selector selector() {
return new SelectorImpl();
}
public static void main(String[] args) {
Outer_3 outer3 = new Outer_3();
Selector selector = outer3.selector();
System.out.println(selector.end());
}
}
匿名内部类
匿名内部类的使用基本上需要符合一下几点:
- 匿名内部类只能使用一次,创建匿名内部类的同时也会创建该类的一个对象,之后该类的定义消失。通常用来简化代码编写。
- 匿名内部类内部无法定义构造函数
- 匿名内部类不能有静态成员变量或静态方法
- 匿名内部类是局部内部类,所以局部内部类的限制匿名内部类也有
- 匿名内部类必须继承某个类或者实现某个接口(因为匿名,所以无法访问,要想使用只能通过向上转型为父类或者接口)
匿名内部类的典型应用是用来开启一个线程:
public class Main{
public static void main(String[] args){
Runnable r = new Runnable(){
public void run(){
System.out.println("new Tread is running");
}
};
Thread thread = new Thread(r);
thread.start();
}
}
局部内部类:
//局部内部类
public class Out_4 {
public void inner(final String name) { //jdk8以下必须用final修饰,jdk8虽然不是必须,但是在类内部也是无法改变该变量的。
class Inner {
private String sname;
Inner(){
//name = name = ""; 编译错误,局部内类部无法改变方法参数
this.sname = name;
}
Out_4 getOut() {
return Out_4.this;
}
}
System.out.println(new Inner().sname);
System.out.println(new Inner().getOut());
}
public static void main(String[] args) {
Out_4 out_4 = new Out_4();
out_4.inner("out_4");
//out_4.new Inner(); 在局部外部类所在的方法外部无法访问局部内部类
}
}
嵌套内部类(静态内部类)
public class Out_5 {
private int i;
static private String j;
public Out_5(int i,String jj){
this.i = i;
j = jj;
}
public static void staticMethod(){
}
static public class Inner {
public int x;
private int y;
public Inner(int x,int y){
this.x = x;
this.y = y;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void print(){
System.out.println(j+":"+x+":"+y);;
staticMethod();;
//System.out.println(i); //静态内部类不能访问外部类的非静态成员
}
}
public static void main(String[] args) {
Out_5.Inner inner = new Inner(1,2);
Out_5.Inner inner1 = new Inner(3,4);
inner.print(); //null:1:2
inner1.print(); //null:3:4
Out_5 out_5 = new Out_5(5,"10");
System.out.println(out_5.i+":"+out_5.j); //5:10
Out_5 out_ = new Out_5(5,"15");
System.out.println(out_.i+":"+out_.j); //5:15
inner.print(); 15:1:2
}
}
静态内部类能够访问外部类的静态成员,除了创建时要在前面加上外部类名称.之外,跟普通静态类没什么区别。
静态内部类的特殊用途:接口内部的嵌套类。你放到接口中的类自动是public和static的,并不违反接口的语法。
通常情况下,接口内部不能放置任何代码,但如果你想要实现该接口的所有实现类共享一段公共代码,可以考虑在接口内定义静态类。
这有点类似于抽象类的非抽象方法。
//接口类ClassInInterface
public interface ClassInInterface {
void f();
class Test{ //接口中的类自动是static,所以不需要额外加static
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
//接口实现类
public class ClassInInterfaceImpl implements ClassInInterface {
@Override
public void f() {
System.out.println("method f()");
}
public static void main(String[] args) {
ClassInInterfaceImpl instance = new ClassInInterfaceImpl();
Test test = new Test();
test.setName("name");
System.out.println(test.getName());
}
}
new 和 this
非嵌套类情况下,内部类拥有对外部类的全部访问权,内部类内部拥有一条外部类的引用,那么如何在内部类中得到外部类的引用呢,这就是this的作用了。另外内部类的创建依赖于外部类的某个实例对象,如何由外部类对象创建一个内部类对象,这就需要用到new的新用法。示例如下
public Outer{
class Inner{
private String name;
Inner(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public Outer getOuter(){
//外部类名字.this
return Outer.this;
}
}
public static void main(String[] args){
Outer out = new Outer();
//外部对象.new 内部类构造器(匿名内部类无法用这种方式,但匿名内部类通用可以访问到外部类)
Inner inner = out.new Inner("inner");
System.out.println(inner.getName());
Outer out2 = inner.getOuter();
System.out.println(out==out2); // true
}
}