Java核心技术学习--第四天
第五章 继承
反射
能够分析类能力的程序称为反射。
Class类
捕获异常
将可能抛出的已检查异常的一个或多个方法调用代码放在try块中,然后在catch子句中提供处理器代码。
try
{
String name = ...;
Class c1 = Class.forName(name);
do something with c1
}
catch(Exception e)
{
e.printStackTrace();
}
如果类名不存在,将跳过try块中的剩余代码,程序直接进入catch子句。
java.lang.Class
- static Class forName(String className) 返回描述类名为className的Class对象
- Object newInstance() 返回这个类的一个新实例
java.lang.Throwable
- void printStackTrace() 将Throwable对象和栈的轨迹输出到标准错误流
利用反射分析类的能力
Class类中的getFields\getMethods\getConstructos方法将分别返回类提供的public域、方法和构造器数组。
Class类的getDeclaredFields、getDeclaredMethods、getDeclaredConstructors分别返回类中声明的全部域、方法和构造器,包括私有和受保护成语。
java.lang.Class
- Field[] getFields() 返回一个包含Field对象的数组,记录了这个类或其超类的公有域
- Field[] getDeclaredFields() 返回一个包含Field对象的数组,记录了这个类的所有域
- Method[] getMethods() 返回所有的共有方法,包括从超类继承的公有方法
- Method[] getDeclaredMethods() 返回这个类或接口的全部方法,但不包括由超类继承了的方法
- Constructor[] getConstructos() 返回Class对象所描述的类的所有公有构造器
- Constructor[] getDeclaredConstructos() 返回Class对象所描述的类的所有构造器
java.lang.refllect.Field
java.lang.reflect.Method
java.lang.reflect.Constructor
- Class getDeclaringClass() 返回用于描述类中定义的构造器、方法或域的Class对象
- Class[] getExceptionTypes() (在Constructos和Method类中)返回一个用于描述方法抛出异常类型的Class对象数组
- int getModifiers() 返回一个用于描述构造器、方法或域的修饰符的整型数值。
- String getName() 返回一个用于描述构造器、方法或域名的字符串
- Class[] getParameterTypes() (在Constructor和Method类中)返回一个用于描述参数类型的Class对象数组
- Class getReturnType() (在Method类中)返回一个用于描述返回类型的Class对象
在运行时使用反射分析对象
java.lang.reflect.AccessibleObject
- void setAccessible(boolean flag) 为反射对象设置可访问标志
- boolean isAccessible() 返回反射对象的可访问标志的值
- static void setAccessible(AccessibleObject[] array, boolean flag) 设置对象数组可访问标志
java.lang.Class
- Field getField(String name) 返回指定名称的公有域
- Field getDeclaredField(String name) 返回给定名称的域
java.lang.reflect.Field
- Object get(Object obj) 返回obj对象中用Field对象表示的域值
- void set(object obj, Obejct newValue) 用一个新值设置obj对象中Field对象表示的域
使用反射编写泛型数组代码
java.lang.reflect.Array
- static Object get(Object array, int index) 返回存储在给定位置上的给定数组的内容
- static xxx getxxx(Object array, int index) 返回存储在给定位置上的给定数组的内容
- static void set(Object array, int index, Object newValue) 将一个新值存储到给定位置上的给定数组中
- static xxx setxxx(Object array, int index, Object newValue) 将一个新值存储到给定位置上的给定数组中
- static int getLength(Object array) 返回数组的长度
- static Object newInstance(Class componentType, int length) 返回一个具有给定类型、给定维数的新数组
调用任意方法
java.lang.reflect.Method
- public Object invoke(Object implicitParameter, Object[] explicitParameters)
继承的设计技巧
1、把公共操作和域放在超类
2、不要使用受保护的域
3、除非所有继承的方法都有意义,否则不要使用继承
4、在覆盖方法时,不要改变预期的行为
5、使用多态,而非类型信息。使用多态方法或接口编写的代码比使用多种类型进行检测的代码更加易于维护和扩展。
6、不要过多地使用反射。编译器很难帮助人们发现程序中的错误。
第六章 接口、lambda表达式与内部类
一个类可以实现一个或多个接口。
接口
接口概念
接口不是类,而是对类的一组需求描述。
让类实现一个接口:
- 将类声明为实现给定的接口
- 对接口中的所有方法进行定义
在接口中所有方法都自动是public,但是实现接口时必须把方法声明为public。
java.lang.Comparable
- int compareTo(T other)
java.util.Arrays
- static void sort(Object[] a) 使用mergesort算法对数组a中的元素进行排序
java.lang.Integer
- static int compare(int x, int y)
java.lang.Double
- static int compare(double x, double y)
接口的特性
不能构造接口的对象,能声明接口的变量。
接口变量必须引用实现了接口的类的对象。
可以使用instanceof检查一个对象是否属于某个特定类。
接口可以被扩展。
虽然在接口中不能包含实例域或静态方法,却可以包含常量。
接口中的方法自动设置为public,接口中的域自动设为public static final。
接口与抽象类
abstract class Comparable
{
public abstract int compareTo(Object other);
}
静态方法
默认方法
为接口方法提供一个默认实现。使用default修饰符。
解决默认方法冲突
超类优先。接口冲突。
接口实例
接口与回调
javax.swing.JOptionPane
- static void showMessageDialog(Component parent, Object message) 显示包含一条消息和OK按钮的对话框,位于parent组件的中央。
javax.swing.Timer
- Timer(int interval, ActionListener listener) 构造一个定时器。每隔interval毫秒通告listener一次。
- void start() 启动定时器。启动成功调用监听器的actionPerformed。
- void stop() 停止定时器。停止成功不再调用监听器的actionPerformed。
Comparator接口
对象克隆
lambda表达式
为什么引入lambda表达式
lamda表达式的语法
参数,箭头(->),以及一个表达式
(String first, String second)->
{
if(first.length() < second.length()) return -1;
else if(first.length() > second.length()) return 1;
else return 0;
}
如果没有参数也要提供空括号。
如果一个lambda表达式只在某些分支返回一个值,而在另外一些分支不返回值,是不合法的。
函数式接口
对只有一个抽象方法的接口,需要这种接口的对象时,可以提供一个lambda表达式,这种接口称为函数式接口。
方法引用
用::操作符分隔方法名与对象或类名
- object::instanceMethod
- Class::staticMethod
- Class::instanceMethod
构造器引用
int[]::new等价于x->new int[x]
变量作用域
lambda表达式中捕获的变量必须实际上是最终变量,即初始化之后不会再赋新值。
处理lambda表达式
使用lambda表达式重点是延迟执行。
再谈Comparator
内部类
内部类可以访问该类定义所在的作用域中的数据,包括私有数据。
内部类可以对同一个包中的其他类隐藏起来。
使用内部类访问对象状态
内部类的特殊语法规则
表达式OuterClass.this表示外围类引用。
在外围类的作用域之内,引用内部类:OuterClass.InnerClass
内部类中声明的所有静态域都final。
内部类不能有static方法。
内部类是否有用、必要和安全
局部内部类
在一个方法中定义局部类。
局部类不能用public或者private访问符声明,作用域被限定在块中。
由外部方法访问变量
局部类可以访问局部变量,局部变量必须事实上为final。
匿名内部类
创建一个实现接口的类的新对象,需要实现的方法定义在括号{}内。
new SuperType(construction parameters)
{
inner class methods and data
}
匿名类不能有构造器,将构造器参数传递给超类构造器。
public void start(int interval, boolean beep)
{
Timer t = new Timer(inteerval, event->
{
System.out.println("At the tone, the time is " + new Data());
if(beep) Toolkit.getDefaultToolkit().beep();
});
t.start();
}
public void start(int interval, boolean beep)
{
Actionlistener listener = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is " + new Data());
if(beep) Toolkit.getDefaultToolkit().beep();
}
}
Timer t = new Timer(interval, listener);
t.start();
}
建立Object的一个匿名子类的一个匿名对象,getEnclosingClass则得到其外围类,也就是包含这个静态方法的类。
new Object(){}.getClass().getEnclosingClass()
静态内部类
把内部类声明为static,取消产生的引用。只有内部类可以声明为static。
与常规内部类不同,静态内部类可以有静态域和方法。
声明在接口中的内部类自动成为static和public类。