Java内部类
一、成员内部类
内部类可以拥有private、protected、public、包(默认) 访问权限。
外部类只能public和包 访问权限。
成员内部类可以无条件访问外部类所有成员属性和方法(包括private和静态成员)
当内部类外部类存在同名变量或者方法,默认访问内部类,外部类需要按照下面格式访问
外部类.this.成员变量
外部类.this.成员方法
class OutClass{
private int a = 1;
public static int b = 2;
private InClass inner = null;
public InClass getInnerInstance(){
if(null == inner){
inner = new InClass();
return inner;
}
}
class InClass{
int a = 3 ;
int b = 4;
public void doSomethings(){
System.out.print(a);
System.out.print(b);
System.out.print(OutClass.this.a);
System.out.print(OutClass.this.b);
}
}
}
如果创建内部类对象,必须存在一个外部类对象,方法如下;
public class Test {
public static void main(String[] args) {
//第一种方式:
OutClass outter = new OutClass();
OutClass.InClass inner = outter.new Inner();
//第二种方式:
OutClass.InClass inner1 = outter.getInnerInstance();
}
}
关于成员内部类的继承问题。一般来说,内部类是很少用来作为继承用的。但是当用来继承的话,要注意两点:
1)成员内部类的引用方式必须为 Outter.Inner.
2)构造器中必须有指向外部类对象的引用,并通过这个引用调用super()。这段代码摘自《Java编程思想》
class WithInner {
class Inner{
}
}
class InheritInner extends WithInner.Inner {
// InheritInner() 是不能通过编译的,一定要加上形参
InheritInner(WithInner wi) {
wi.super(); //必须有这句调用
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner obj = new InheritInner(wi);
}
}
二、局部内部类
局部内部类是定义在一个方法或者作用域里面的类,访问权限仅限于该方法内或者该作用域内。
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
}
三、匿名内部类(常见使用)
匿名内部类是唯一一个没有构造器的类,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。匿名内部类用于集成其他类或者实现接口,并不需要增加额外的方法,只对继承的方法进行实现或者重写。下来是监听器的例子。
scan_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
history_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
作用和下面完全一模一样
private void setListener()
{
scan_bt.setOnClickListener(new Listener1());
history_bt.setOnClickListener(new Listener2());
}
class Listener1 implements View.OnClickListener{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
class Listener2 implements View.OnClickListener{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
四、静态内部类
静态内部类和成员内部类的定义区别只是前面多了一个关键字static。用法和普通成员变量和静态成员变量极为相似。静态内部类不需要依赖于外部类,成员内部类必须依赖外部类的对象。
静态内部类是不依赖于外部类的,也就说可以在不创建外部类对象的情况下创建内部类的对象。另外,静态内部类是不持有指向外部类对象的引用的
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
问题:
1.为什么成员内部类可以无条件访问外部类的成员?
编译器会默认为成员内部类添加了一个指向外部类对象的引用,虽然我们在定义的内部类的构造器是无参构造器,编译器还是会默认添加一个参数,该参数的类型为指向外部类对象的一个引用,所以成员内部类中的Outter this&0 指针便指向了外部类对象,因此可以在成员内部类中随意访问外部类的成员。从这里也间接说明了成员内部类是依赖于外部类的,如果没有创建外部类的对象,则无法对Outter this&0引用进行初始化赋值,也就无法创建成员内部类的对象了。
2.为什么局部内部类和匿名内部类只能访问局部final变量?
public class Test {
public static void main(String[] args) {
}
public void test(final int b) {
final int a = 10;
new Thread(){
public void run() {
System.out.println(a);
System.out.println(b);
};
}.start();
}
}
如果局部变量的值在编译期间就可以确定,则直接在匿名内部里面创建一个拷贝。如果局部变量的值无法在编译期间确定,则通过构造器传参的方式来对拷贝进行初始化赋值。但是存在test方法跑完了,新起的线程还没跑完,继续用,而且还是另外的作用域使用,所以必须限定不可以变,即添加final修饰。
注:java8可以不显示修饰为final,但是编译的过程,会自动在复制过去的值中添加final 关键字,达到数据一致性的目的。
为什么java需要内部类,总结一下主要有以下四点:
1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码
个人觉得第一点是最重要的原因之一,内部类的存在使得Java的多继承机制变得更加完善。
内部类笔试面试题目:
1、根据注释添加代码
public class Test{
public static void main(String[] args){
// 初始化Bean1
(1)
bean1.I++;
// 初始化Bean2
(2)
bean2.J++;
//初始化Bean3
(3)
bean3.k++;
}
class Bean1{
public int I = 0;
}
static class Bean2{
public int J = 0;
}
}
class Bean{
class Bean3{
public int k = 0;
}
}
从前面可知,对于成员内部类,必须先产生外部类的实例化对象,才能产生内部类的实例化对象。而静态内部类不用产生外部类的实例化对象即可产生内部类的实例化对象。
创建静态内部类对象的一般形式为: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()
创建成员内部类对象的一般形式为: 外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()
1、Test test = new Test();
Test.Bean1 bean1 = test.new Bean1();
2、Test.Bean2 b2 = new Test.Bean2();
3、Bean bean = new Bean();
Bean.Bean3 bean3 = bean.new Bean3();
2。代码输出啥
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
outter.new Inner().print();
}
}
class Outter
{
private int a = 1;
class Inner {
private int a = 2;
public void print() {
int a = 3;
System.out.println("局部变量:" + a);//3
System.out.println("内部类变量:" + this.a);//2
System.out.println("外部类变量:" + Outter.this.a);//1
}
}
}
参考:海子的博客