Java核心编程三:类的继承反射接口和内部类
Posted zzulp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java核心编程三:类的继承反射接口和内部类相关的知识,希望对你有一定的参考价值。
1 继承
1.1 继承的实现 继承的基本语法如下:class Manage extends Employee
public Manage()
super();
//Manage member init
Java采用关键字extends来替换C系统中的:来标识继承,但只支持公有继承。 1.2 构造函数 派生类的构造函数如果要初始化基类,则必须至于第一行调用super();C++则需要在初始化列表中调用基类名称的构造器。
如果没有显式的调度,则是编译器调用基类的默认构造函数。此时若基类没有默认构造函数,但存在其他构造函数,则编译过程出错。
1.3 多态 对于基类的私有成员,派生类只能通过基类的方法来获取,并通过super告诉编译器,去调用基类上的方法。
在JAVA中对象变量是多态的,不需要像C++中必须使用引用或指针才能实现多态。并且多态行为是默认的,不需要将方法声明为虚拟。但若希望实现多态,仍然需要在基类中实现此方法的一个版本,并在派生类中进行覆盖。
如果想让一个方式或属性不能被子类覆盖,可以声明为final方法。若一个类不希望有子类,可以声明为final类。
在覆盖一个方法时,其可见性不能被缩小。
1.4 动态绑定 动态绑定是指在运行时索引正确对象上的正确方法的技术。可以在运行时进行查找。Java对此进行了优化,在编译期将所有调用的路径记录下来,并保存起来,运行时只需要查找此表即可。
1.5 类型转换 派生类型可以轻易的转换为基类型,但向下的转换可能会导致运行时类型错误,因而在转换时要用instanceof来检验,这点也适用于null对象。
1.6 抽象类 可以使用abstract关键字声明方法,这样的方法将不包含实现体。而包含了抽象方法的类必须声明为抽象类。 抽象类也可以包含属性和非抽象方法,但其不能实例化。当然我们仍可以定义抽象类的变量来引用子类对象。 子类可以实现部分抽象方法,但这样子类也必须是抽象的。若实现了全部抽象方法,子类便不再抽象。 对于不包含抽象方法的类,也可以声明为抽象的。
abstract class Person
abstract String getName();
2 Object类 Java中所有类都继承自Object类。除了原始类型外,所有形式的数据也都继承自Object. equals() 和== 一样通过比较两个对象是否指向同一对象来比较相等。 hashCode() 计算对象的散列码 toString() 导出对象的字符串表示,这样当将对象送给print时,会自动调用对象的toString。
3 泛型数组列表 ArrayList<T>(capacity) 构造一个指定容量大小的列表 add(T) 增加一个元素 ensureCapacity() 扩展容器空间 size() 返回元素个数 trimToSize() 收缩到指定个数 get(index) 返回指定位置上的元素 set(idx,T) 设置指定位置元素 remove(idx) 移除指定位置元素
4 box与unbox 基本类型都有与之对应的类类型,而且可以方便的从基本类型转换为类类型。而泛型类不支持基本类型的元素。 需要注意的是这两个操作是编译器来完成的,而不是由虚拟机来实现的。
5 反射 5.1 Class Class类类专门用于保存Java类的元信息,有三种方式获取到它的实例。 I 调用对象的getClass()可以返回此类的实例,其中保存了java类的属性信息,如类名、字段名、方法名等。 II 通过静态函数和类名来生成:Class.forName(strName) III 访问类型的属性,T.class 可以通过元类对象来创建对象实例,调用newInstance()即可。 5.2 分析类的接口 getFields() 将返回类的所有属性数组,包括基类,只有public的 getDeclaredFields() 返回类属性数组,不包括基类 getField(String name) 根据字段名称返回指定域,返回类属性,不包括基类,必须为public
getMethods() //返回类包括基类的方法 getDeclaredMethod(String name,Class[] parmType) //根据指定的参数类型数据返回指定的参数
getConstructors() getDeclaredConstructors()
Field类保存了类的字段属性信息 Method类保存了方法属性信息 Constructor类保存了构造器的属性信息 Modifier类保存声明的修改器的信息如static ,private等
在得到了这些类后,可以调用其上的方法 getExceptionType() 获取方法抛出的异常类型的元类数组 getModifiers() 其返回一个整数,结果可以用isAbstract() isFinal(),isInterface(),isPrivate(),...,isStatic()来分析 getName() 获取方法、属性或构造函数的名字 getParameterTypes() 返回构造函数或方法的参数类型元类数组 getReturnType() 返回方法的返回值的类型元类
5.3 分析对象的接口 AccessibleObject是Field,Method等的基类。其上有如下方法,可以另子类调用。 setAccessible(flag) 设置字段的可访问性,对于private字段,反射只有设置为true时,才可访问。 isAccessible()
通过类获取类对象应该有的Field对象后,可以获取或设置域在对象上的值。 Object get(object) void set(obj,newVal)
5.4 方法指针 通过Method的实例,可以拿到一个方法的指针。它可以通过Object invode(obj,Object [])来进行调用。对于静态方法,obj为null。 其返回结果是Object类型的,因此需要进行一定的类型转换。
5.5 反射示例
public class TestReflect
public int value;
public String name;
public TestReflect()
value = 1;
name = "lipeng";
public void function(String s)
System.out.println(s);
public static void main(String[] args)
TestReflect rf = new TestReflect();
try
Field field = rf.getClass().getField("name");
Method method = rf.getClass().getDeclaredMethod("function", String.class);
String val = field.get(rf).toString();
System.out.println(val);
method.invoke(rf, "Hello world");
catch(Exception e)
e.printStackTrace(System.out);
6 枚举类型 声明类型:enum Week MONDAY,TUESDAY,...; 声明对象:Week week = Week.MONDAY; enum声明的类型都继承自Enum类,它有一个静态方法values()返回所有常量的数组。 enum对象还可通过Enum的静态方法valueOf(Class eType,String val)来设置一个枚举类型的常量值。
7 接口 7.1 接口声明 必须在单独的文件中声明接口,文件名与接口名相同。
interface IRule
int PI = 3.14;
int method();
class ConRule implements IRule
public int method();
接口中的方法自动为public的,不需要特殊声明,但在实现类中,必须声明为public的,否则便变为包可见的。接口中不能声明静态方法和实例属性,只能声明常量,且被自动标记为public static final。
接口也可以实现为泛型类型如
interface IRule<T>
int method(T arg);
class ConRule implements IRule<Person>
int method(Person p)
printf(p.toString());
Java语言提供了Comparable类和Comparable<T>两个接口,前者接受Object类型的参数,后者接受T类型的参数。
7.2 接口使用 interface rule = new ConRule();// 接口类不能用new实例化,但可以通过声明变量指向实现接口的对象。
可以使用instanceof判断对象是否实现了接口。
接口之间可以进行继承,且支持多重继承。之所有引入接口,是因为其不允许多类的重继承。
7.3 接口与回调 Timer类可以接受一个对象,以定时执行一些回调函数。只要这个对象实现了特定的接口即可。 java.util.Timer包含了所需要的后台调度类,只需要实现TimerTask.run()方法即可。
8 对象复制 在Object基类提供了一个受保护的clone()方法,可以返回对象的一个浅拷贝。通常情况下,这并不是你想要的,因此需要像C++一样,在自己的类中实现自己的clone()函数,以覆盖基类的行为。
只有需要实现深copy的类,才需要自己实现clone()接口。
9 内部类 Java的内部类有以下三个特点: 1 内部类的方法可以访问此类所定义的外部类作用域中的数据,包括私有数据。 2 内部类可以对同一个包中的其他类隐藏起来。 3 当需要定义一个回调函数时,可以使用匿名内部类。 9.1 内部类访问外部对象状态 内部类可以定义为private的,这样其只在外部类的内部可见。编译器会为内部类合成构造函数,或为其构造函数添加一个指向外部类对象实例的引用。这样使得其可以访问到其外部类对象。 9.2 内部类使用语法 在外部类创建内部类: Outobj.new InnerClass(params) 在外部类作用域外,引用内部类:OuterClass.InnerClass 9.3 内部类实现 内部类可以访问外部类的私有成员,是一个编译器现象,JVM并不了解这个事情。为了实现这个目的,编译器会将外部类的对象this指针传递给内部类,并在外部类上增加相应的static函数,以访问外部类的相应私有成员。 如果不希望内部类引用外部类,则可以将其声明为static的。 9.4 方法内部类 可以在方法中定义内部类。方法中的内部类,可以访问外部方法的final类型的常量局部变量。 编译器的实现更为简单,将内部类所引用的外部局部变量作为构造器参数复制给类,并作为其成员。 9.5 匿名内部类 如果类只使用一次,则可以创建为匿名的。使用语法为:
Type val = new SuperType(cons paras)
//内部类的方法及数据定义
匿名内部类如果过长,会不利于代码的理解,应该限制使用。 示例:
public class TimerTest
public static void main(String[] args)
Timer t = new Timer();
// class myTask extends TimerTask
//
// public void run()
//
// System.out.printf("Runing at %s \\n",new Date());
//
//
// TimerTask task = new myTask();
TimerTask task = new TimerTask()
public void run()
System.out.printf("Runing at %s \\n",new Date());
;
t.schedule(task, 0, 1000);
try
Thread.sleep(10000);
catch (InterruptedException e)
// TODO Auto-generated catch block
e.printStackTrace();
t.cancel();
10 反射代理 代理是一种支持在运行时创建支持特定接口的类对象的方法,类的代码可以通过类加载器从远程或本地进行加载。 Object Proxy.newProxyInstance(ClassLoader cl,Class[] interfaces,InvocationHandler ih) Object invoke(Object proxy,Method method,Object[] args) 而被代理的对象,则通过实现InvocationHandler接口的invoke()方法将对象进行包装。 这里有个要求,就是被代理的类需要实现了特定的接口,如果一个类不是实现自接口,则无法这样使用。
import java.lang.reflect.*;
import java.util.Arrays;
public class ProxyTest
public static void main(String[] args)
Object[] elements = new Object[1000];
for(int i = 1;i<elements.length;i++)
Integer value = i ;
Class[] interfaces = value.getClass().getInterfaces();
InvocationHandler handler = new TracekHandler(value);
Object proxy = Proxy.newProxyInstance(null, interfaces, handler);
elements[i] = proxy;
int result = Arrays.binarySearch(elements, 300);
if(result>=0)
System.out.println(elements[result]);
class TracekHandler implements InvocationHandler
public TracekHandler(Object target)
this.target = target;
public Object invoke(Object proxy,Method m,Object[] args) throws Exception
System.out.print(target);
System.out.print("."+m.getName()+"(");
if(args!=null)
System.out.println(")");
return m.invoke(target, args);
private Object target;
以上是关于Java核心编程三:类的继承反射接口和内部类的主要内容,如果未能解决你的问题,请参考以下文章