Java -- 内部类详解

     学习《Java核心技术》这本书,已经看到了内部类,分享一下学习心得和体会

内部类是定义在另一个类中的类,那么问题就来了:为什么要使用内部类呢?,定义它有什么好处?

首先回答第一个问题

内部类提供了更好的封装

只有外部类能访问内部类内部类可以独立继承一个接口,不受外部类是否继承接口影响内部类中的属性和方法即使是外部类也不能直接访问

相反内部类可以直接访问外部类的属性和方法,即使private利于回调函数的编写


   内部类(Inner Class),类似的概念在C++里也有,那就是嵌套类(Nested Class),乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用心良苦。学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构。

   内部类语法比较复杂,我们首先用一个简单但不实用的例子说明一下:构造一个语音时钟提供两个参数,时间间隔和开关铃声

package com.Interface;

import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

import javax.swing.JOptionPane;
import javax.swing.Timer;

public class InnerClassTest {
	public static void main(String[] args) {
		TalkingClock clock = new TalkingClock(1000,true);
		clock.start();
		
		//keep program running util user selects "ok"
		JOptionPane.showInternalMessageDialog(null, "Quit program");
		System.exit(0);
	}
}
	//A clock that ptints the time in regular intervals
	class TalkingClock{
		private int interval;//时间间隔
		private boolean beep;//嘟嘟声
		
		//Constructor a talking clock
		public TalkingClock (int interval, boolean beep) {
			this.interval= interval;
			this.beep = beep;
		}
		
		//starts the clock
		public void start() {
			ActionListener listener = new TimePrinter();
			Timer t = new Timer(interval, listener);
			t.start();
			}
		
		public class TimePrinter implements ActionListener
		{
			public void actionPerformed(ActionEvent event)
			{
				System.out.println("At the tone , the time is " + new Date());
				if (beep) {
					/*Toolkit():这个类是抽象窗口工具箱所有实际实现的抽象超类。
					 *  getDefaultToolkit():默认工具包
					 *  beep():根据本机系统设置和硬件功能发出音频beep。
					 */
					Toolkit.getDefaultToolkit().beep();
				}
		    }
		}

	}

  TimePrinter类就是一个内部类,它的外部类是TalkingClock类,内部类既可以访问自身的数据,也可以访问创建它的外部类对象的数据域。

  广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类,接下来我们逐一分析

1.成员内部类

  成员内部类是最普通的内部类,它的定义为位于另一个类的内部。就像上面代码一样   TimePrinter类就是一个内部类,它的外部类是TalkingClock类。

不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:

外部类.this.成员变量
外部类.this.成员方法


    虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。 在外部类中如果要访
问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:成员内部类是依附外部类而存在的,也就是
说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

 2.局部内部类

  局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

class People{
    public People() {
         
    }
}
 
class Man{
    public Man(){
         
    }
     
    public People getWoman(){
        class Woman extends People{   //局部内部类
            int age =0;
        }
        return new Woman();
    }
}

  注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

  3.匿名内部类

  匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。下面这段代码是一段Android事件监听代码:

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
                 
            }
        });

  这段代码为两个按钮设置监听器,这里面就使用了匿名内部类。这段代码中的:

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修饰符的。

  匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

 4.静态内部类

[java] view plain copy
package cn.com.qiang.neibulei2;  
  
public class MyOuter2 {  
    public static int x=100;  
      
    public static class MyInner{  
        private String y="Hello!";  
          
        public void innerMethod(){  
            System.out.println("我是内部类 x = "+x);  
            System.out.println("我是内部类 y = "+y);  
        }  
    }  
  
     /** 
      * @param args 
      */  
     public static void main(String[] args) {  
         MyOuter2.MyInner si = new MyOuter2.MyInner();//静态内部类不通过外部实例就可以创建对象;与类变量可以通过类名访问相似  
         si.innerMethod();  
      // TODO Auto-generated method stub  
     }  
}   
执行结果如下:
class People{
    public People() {
         
    }
}
 
class Man{
    public Man(){
         
    }
     
    public People getWoman(){
        class Woman extends People{   //局部内部类
            int age =0;
        }
        return new Woman();
    }
}

我是内部类 x = 100  
我是内部类 y = Hello!  

java内部类总结

1、 在方法间定义的非静态内部类:

1)外围类和内部类可互相访问自己的私有成员。

2)内部类中不能定义静态成员变量。
      在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象

2、 在方法间定义的静态内部类:

1)只能访问外部类的静态成员。
       静态内部类没有了指向外部的引用

3、在方法中定义的局部内部类:

1)该内部类没有任何的访问控制权限
2)外围类看不见方法中的局部内部类的,但是局部内部类可以访问外围类的任何成员。
3)方法体中可以访问局部内部类,但是访问语句必须在定义局部内部类之后。
4)局部内部类只能访问方法体中的常量,即用final修饰的成员。


4、在方法中定义的匿名内部类:

1)没有构造器,取而代之的是将构造器参数传递给超类构造器

      当你只需要创建一个类的对象而且用不上它的名字时,使用匿名内部类可以使代码看上去简洁清楚。

本文参考:Java高级类 和  java中的内部类完全总结


小伙伴们可以关注我的公众号,留言必回复哦


Java核心基础

----------------------------------

长按关注哦(看那两撇小胡子)

基础 | 心得 | 经历 | 更重要的是开心嘛!


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值