现在的位置: 首页 > 综合 > 正文

java内部类

2018年02月04日 ⁄ 综合 ⁄ 共 5409字 ⁄ 字号 评论关闭

内部类是定义在另一个类中的类,为什么需要内部类呢?其主要原因有以下三点:

1、内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。

2、内部类可以对同一个包中的其他类隐藏起来。

3、当要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。

内部类的共性:

1、内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。

2、内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。

3、内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。

java内部类分为: 成员内部类、方法内部类(局部内部类)、匿名内部类、静态嵌套类 。

成员内部类:

通俗的说就是把内部类当做外部类的成员

package com.stone.InnerClassTest;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;

public class InnerClassTest
{
   public static void main(String[] args)
   {
      TalkingClock clock = new TalkingClock(1000, true);
      clock.start();

      JOptionPane.showMessageDialog(null, "Quit program?");
      System.exit(0);
   }
}

class TalkingClock
{
   public TalkingClock(int interval, boolean beep)
   {
      this.interval = interval;
      this.beep = beep;
   }

   public void start()
   {
      ActionListener listener = new TimePrinter();
      Timer t = new Timer(interval, listener);
      t.start();
   }

   private int interval;
   private boolean beep;

   public class TimePrinter implements ActionListener
   {
      public void actionPerformed(ActionEvent event)
      {
         Date now = new Date();
         System.out.println("At the tone, the time is " + now);
         if (beep) Toolkit.getDefaultToolkit().beep();
      }
   }
}

局部内部类:

把类放在方法内
class Outer {
	public void doSomething() {
		class Inner {
			public void seeOuter() {
			}
		}
	}
}

(1)、局部内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。
(2)、局部内部类对象不能使用该内部类所在方法的非final局部变量
因为方法的局部变量位于栈上,只存在于该方法的生命期内。当一个方法结束,其栈结构被删除,局部变量成为历史。但是该方法结束之后,在方法内创建的内部类对象可能仍然存在于堆中!例如,如果对它的引用被传递到其他某些代码,并存储在一个成员变量内。正因为不能保证局部变量的存活期和方法内部类对象的一样长,所以内部类对象不能使用它们。
下面是完整的例子:

package com.stone.LocalInnerClassTest;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;

public class LocalInnerClassTest
{
   public static void main(String[] args)
   {
      TalkingClock clock = new TalkingClock();
      clock.start(1000, true);

      JOptionPane.showMessageDialog(null, "Quit program?");
      System.exit(0);
   }
}

class TalkingClock
{
   public void start(int interval, final boolean beep)
   {
      final String methodname="methodname"; //不声明为final,编译报错
      class TimePrinter implements ActionListener
      {
         public void actionPerformed(ActionEvent event)
         {
            Date now = new Date();
            System.out.println("At the tone, the time is " + now);
            System.out.println(methodname);
            if (beep) Toolkit.getDefaultToolkit().beep();
         }
      }
      
      ActionListener listener = new TimePrinter();
      Timer t = new Timer(interval, listener);
      t.start();
   }
}

匿名内部类

将局部内部类的使用在深入一步。假如只创建这个类的一个对象,就不必命名。这种类被称为匿名内部类顾名思义。
当程序中使用匿名内部类时,在定义匿名内部类的地方往往直接创建该类的一个对象。匿名内部类的声明格式如下:
new SuperType(construction parameters){
    inner class methods and data
}

什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的。

1、只用到类的一个实例 。

2、类在定义后马上用到。

3、类非常小(SUN推荐是在4行代码以下)

4、给类命名并不会导致你的代码更容易被理解。

在使用匿名内部类时,要记住以下几个原则:

1、匿名内部类不能有构造方法。

2、匿名内部类不能定义任何静态成员、静态方法。

3、匿名内部类不能是public,protected,private,static。

4、只能创建匿名内部类的一个实例。

5、一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。

6、因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。

匿名内部类根据其实现方式的不同分为三类:继承式的匿名内部类、接口式的匿名内部类、参数式的匿名内部类。

继承式的匿名内部类:

package com.stone.AnonymousInnerClassTest;

public class ExtendsAnonyInnerClass {
	public void drive() {
		System.out.println("Driving a car!");
	}
	
	public static void main(String[] args) {
		ExtendsAnonyInnerClass car = new ExtendsAnonyInnerClass() {
			public void drive() {
				System.out.println("Driving another car!");
			}
		};
		car.drive();
	}
}

输出结果:

Driving another car!

接口式的匿名内部类

package com.stone.AnonymousInnerClassTest;

interface Vehicle {
	public void drive();
}

public class InterfaceAnonyInnerClass {
	public static void main(String[] args) {
		Vehicle v = new Vehicle() {
			public void drive() {
				System.out.println("Driving a car!");
			}
		};
		v.drive();
	}
}

输出结果:

Driving a car!

参数式的匿名内部类

package com.stone.AnonymousInnerClassTest;

public class ParaAnonyInnerClass {
	public static void main(String[] args) {
		Bar b = new Bar();
		b.doStuff(new Foo() {
			public void foo() {
				System.out.println("foofy");
			}
		});
	}
}
class Bar {
	void doStuff(Foo f) {
		f.foo();
	}
}

interface Foo {
	void foo();
}

我们根据以上的定时器的例子来重写一个匿名内部类实现,此实现方式为接口匿名内部类

package com.stone.AnonymousInnerClassTest;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;

public class AnonymousInnerClassTest {
	public static void main(String[] args) {
		TalkingClock clock = new TalkingClock();
		clock.start(1000, true);

		JOptionPane.showMessageDialog(null, "Quit program?");
		System.exit(0);
	}
}

class TalkingClock {
	public void start(int interval, final boolean beep) {
		ActionListener listener = new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				Date now = new Date();
				System.out.println("At the tone, the time is " + now);
				if (beep)
					Toolkit.getDefaultToolkit().beep();
			}
		};
		
		Timer t = new Timer(interval, listener);
		t.start();
	}
}

静态嵌套类

有的时候内部类只为试了把一个类隐藏在另一个类的内部,并不需要内部类引用外部类的对象。为此,可以将内部类声明为static,以便取消产生的引用。

package com.stone.StaticInnerClassTest;

public class StaticInnerClassTest
{
   public static void main(String[] args)
   {
      double[] d = new double[20];
      for (int i = 0; i < d.length; i++)
         d[i] = 100 * Math.random();
      
      ArrayAlg.Pair p = ArrayAlg.minmax(d);
      System.out.println("min = " + p.getFirst());
      System.out.println("max = " + p.getSecond());
   }
}

class ArrayAlg
{
   public static class Pair
   {
      public Pair(double f, double s)
      {
         first = f;
         second = s;
      }

      public double getFirst()
      {
         return first;
      }

      public double getSecond()
      {
         return second;
      }

      private double first;
      private double second;
   }

   public static Pair minmax(double[] values)
   {
      double min = Double.MAX_VALUE;
      double max = Double.MIN_VALUE;
      for (double v : values)
      {
         if (min > v) min = v;
         if (max < v) max = v;
      }
      return new Pair(min, max);
   }
}

在内部类不需要使用外围类的对象时,应该使用静态内部类。

为什么需要内部类?

典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。

使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。

抱歉!评论已关闭.