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核心编程三:类的继承反射接口和内部类的主要内容,如果未能解决你的问题,请参考以下文章

内部类和匿名内部类的用法

Java内部类

java 内部类的初学习

Java -- 内部类

匿名内部类

JAVA学习之局部内部类,匿名内部类,静态内部类