您的位置:首页 > 编程语言 > Java开发

Java核心编程三:类的继承、反射、接口和内部类

2013-09-19 07:45 323 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐