java学习(12)——内部类(静态方法获取对应类)

内部类(inner class)

内部类是定义在另一个类中的类,使用内部类可以达到很多数据访问上的需要

使用内部类的主要原因:

  • 内部类可以对同一个包中的其他类隐藏
  • 内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据

内部类原本对于简洁的实现回调很重要,现在有了更好的lambda表达式
and
##内部类具有一个指向外层的隐式引用##


  • 在java中,只有内部类能被private修饰

  • 内部类属于编译器现象,编译器会将内部类转换为一般的类文件,而虚拟机对此并不知情,它只知道可用的引用

  • 一般内部类中所有静态字段有必须是final,并且初始化为一个编译时常量。不能有static方法 ,但是语言本身支持使用一个静态方法,但只能访问外围类的静态字段和方法,显然在这种情况下,对比过于复杂的情况,那点得到的好处有些得不偿失

——————————————————————————————————————

在方法中创建一个一次性的局部类

上例子:

public void start()
{
	class TimePrinter implements ActionListener
	{
		public void actionPerformed(ActionEvent event)
		{
			System.out.println("At the tone , the time is"
			+Instant.ofEpochMilli(event.getwhen()));
			if(beep)Toolkit.getDefaultToolkit().beep();
		}
	}
	
	var listener =  new TimePrinter();
	var timer = new Timer(interval ,listener);
	timer.start();
}

局部类的优点:对外界完全隐藏,仅对该start方法显示
★★案例2:通过外部方法获取参数访问局部变量!

局部变量要求是事实最终变量,即赋值以后不会再被改变(具有确定性或者被final修饰)

典型范例:

public void start(int interval.boolean beep)
{
	class TimePrinter implements AcionListener
	{	
		用到参数的值会以final类型复制进来
		System.out.println("At the tone ,the time is"
		+Instant. ofEpochMilli(event.getwhen()));
		if(beep)Toolkit.getDefaultToolkit().beep();
		}
	}
	
	var listener = new TimePrinter();
	var timer = new Timer(interval,listener);
	time.start();

———————————————————————————————————————

匿名内部类

使用内部类的时候,如果只是为了创建单个对象,甚至可以不用指定类的名字,这样创建出来的类就是匿名内部类

public void start(int interval,boolean beep)
{
	var listener = new ActionListener()
	{
		public void  actionPerformed(ActionEvent event)
		{
		System.out.println("At the tone ,the time is"
		+Instant. ofEpochMilli(event.getwhen()));
		if(beep)Toolkit.getDefaultToolkit().beep();
		}
	};
	var timer = new Timer(interval,listener);
	listener.start();
	}
new  超类 (){类的定义}
var 变量 = new 类名 (){类的定义};
  • 匿名内部类,匿去的是本类的名字,直接将本类implements接口或extends超类省略为直接用超类名字。如上例
  • 内部类构造参数会传给父类构造器,只要内部类实现了一个接口,那么它就不能有任何构造参数————会默认引申为Object的子类
  • 尽管匿名类不能有构造器,但是可以提供一个对象初始化块
  • 一般作用:实现事件监听以及其他回调。但是如今最好还是使用lambda表达式

——————————————————————————————————————
相关思路 / 语法

  • 双括号初始化
    利用内部类语法,假如想创建一个数组列表,并且传输到一个方法:
var friends = new ArrayList< String>
friends.add("A");
friends.add("B");
invite(friend);

如果操作后不再需要这个列表,最好将其作为一个匿名列表

invite(new ArrayList< String>(){{add("A");add("B");}});

上述语句中,外层括号建立了ArrayList的一个匿名子类。内层则是一个初始化块

大多数情况下,可以使用List.of(“A”,“B”);代替

  • 建立一个与超类大体类似的情况,对于匿名子类使用equals的时候要思考是否能够完成测试
  • 使用静态方法的时候,通常希望在日志返回对应类名,但静态方法调用getClass的时候是调用this.getClass()而静态方法没有this。
    合适的方法是使用以下语句:
new Object(){}.getClass().getEnclosingClass()

此处,new Object(){ }建立了Object的匿名子类的一个匿名对象,getEnclosingClass则得到其外围类,也就是包含这个静态方法的类

———————————————————————————————————————

静态内部类

有时候,使用内部类只是为了将一个类藏在另一个类的内部,并不需要内部类有外围类对象的一个引用。为此,可以将内部类声明为static。这样就不会生成那个引用。
下面是一个想要使用静态内部类的一个典型例子。任务:计算数组中的最大最小值

首先是方法的思路:遍历一次,记录最大最小值

double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;

for(double v: values)
{
	if(min > v)min = v;
	if(max < v)max = v;
}

这个方法有两个值需要返回,为此可以定义一个包含两个double值的类

class Pair
{
	private double first;
	private double second;

	public Pair(double f,double s)
	{
		first = f;
		second = s;
	}
	public double getFirst(){ return first; }
	public double getSecond(){ return second;}
	}

minmax方法可以返回一个Pair类型的对象

class ArrayAlg
{
	public static Pair minmax(double[ ] values)
	{
	...
	return new Pair(min,max);
	}
}

为了防止重名,最好将Pair定义为内部类,由于是在静态方法中定义,没有办法返回外围类的引用,所以应该使用静态内部类

class ArrayAlg
{
	public static class Pair
	...
	}
...
}
  • 只要内部类不需要访问外围类对象,一般都是使用静态内部类,一些C++沿用过来的习惯是叫它嵌套类
  • 与常规内部类不同,静态内部类可以有静态字段和方法
  • 接口中的内部类自动是static和public

成品:

package 内部类;

/*This program demonstrates the use of static inner classes
 *  demonstrates:演示
 *  @version 1.0 2020/6/24
 *  @author 乐乐想学会java
 *  
 *  
 *  本程序中出现的标示
 *  @version 版本描述
 *  @author  作者描述
 *  @param 自由文本
 *  
 *  
 *  
 * 常用的还有 @see@link,用于创建一个超链接 @see 包路径下某类#方法(double),链接到该方法
 * 或<a href ="... ">label</a>的html标签类型
 * 或直接" " 
 * */

public class StaticInnerClassTest {
	public static void main (String []args)
	{
		//var values = new double[20];貌似版本不是java10,那就不能用var了
		double[] values = new double[20];
		for(int i=0;i<values.length;i++)
			values[i]=100*Math.random();//生成随机数
		ArrayAlg.Pair p = ArrayAlg.minmax(values);
		System.out.println("min="+p.getFirst());
		System.out.println("max="+p.getSecond());
	}
}

class ArrayAlg
{
/*
 * A pair of floating-point numbers
 * */	
public static class Pair
{
	private double first;
	private double second;

/*
 *Constructs a pair from two floating-point numbers
 * @param f the first number
 * @param s the second number
 * */
	public Pair(double f,double s)
	{
		first = f;
		second = s;
		
	}
	/*
	 * Returns the first number of the pair
	 * @return the first number
	 * */
	public double getFirst()
	{
		return first;
	}
	/*
	 * Returns the second number of the pair
	 * @return the second number
	 * */
	
	public double getSecond()
	{
		return second;
	}
	
}
/*
 * Computes both the minimum and the maximum of an array
 * @param values an array of float-point numbers
 * @return a pair whose first element is the minimum and whose second element is the maximum
 * 
 * */

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



}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值