JAVA 构造器,extends[继承],implements[实现],Interface[接口],reflect[反射],clone[克隆],final,static,abstract[抽象]
构造器[构造函数]:
在java中如果用户编写类的时候没有提供构造函数,那么编译器会自动提供一个默认构造函数.它会把所有的实例字段设置为默认值:所有的数字变量初始化为0;所有的布尔变量设置为false;所有对象变量设置为null;
PS:
只有在类中没有其它构造器的时候,系统才会提供默认构造器.如果你希望用户能能够调用不带参数的构造器,那么你就必须自己实现一个.
extends[继承]:
java中的继承,和C++中是有差别的.比如JAVA不支持多重继承。但是JAVA可以通过implements来实现额外的接口.
Example:
DogDeriveClass extends AnimalBaseClass
{
};
这样DogDeriveClass就全盘继承了AnimalBaseClass中的所有方法;但是没有多重继承,那么如果还需要其它功能,那么则可以通过implements关键字来实现需要用到的接口.
Example:
DogDeriveClass extends AnimalBaseClass
Implements Shout, Run
{
void Shot()
{
// Do shout something;
}
void Run()
{
// Do run something;
}
};
从上面代码可以看到,虽然JAVA不支持多重继承,但是派生类可以通过实现接口的方式,来实现本身需要继承过来的功能.
Implements[实现]:
Implements关键字在class声明中使用,以指示所声明的类提供了在implements关键字后面的名称所指定的接口中所声明的所有方法的实现。
接口中的字段[变量]默认是public static final类型; //从接口的调用方式可以看出来. ImplementsInterface.MethedOfInterface();
接口中的方法不能是static,因为static不能被派生类重写,因为如果接口和派生类中都有一个static同名方法,那么根据static的调用方式可以看到
Interface.StaticMethed()即可调用,但是Interface中并没有该方法的实现,只有在具体实现类中有实现,如果有两个派生类都实现了同名的static方法,则该怎么调用?
虚拟机也不知道了!!所以不能这么做.
Example:
public class UserSurfaceView extends SurfaceView
implements Android.view.SurfaceHolder.Callback
{
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int with, int heigh)
{
//TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
//TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
//TODO Auto-generated method stub
}
};
UserSurfaceView类就要实现SurfaceHolder对象中的Callback接口中所声明的所有方法的实现: surfaceChanged/surfaceCreated/surfaceDestroyed
从SDK上看到Android.view是包名,SurfaceHolder是一个public的interface, 而Callback就自然是public static interface[从调用方式即可看出来:Android.view.SurfaceHolder.Callback ]
Interface[接口]:
从上面implements关键字我们已经大概的了解到了关于java中接口的相关知识,下面看看接口的声明:
Example:
public interface Android.view.SurfaceHolder.Callback
{
void surfaceChanged(SurfaceHolder holder, int format, int with, int heigh);
void surfaceCreated(SurfaceHolder holder);
void surfaceDestroyed(SurfaceHolder holder);
};
由于接口中的方法声明默认就是public的,因此不需要特意加上public修饰符.
reflect[反射]:
能够分析类的能力的程序称为反射器,JAVA中提供此功能的包是java.lang.reflect.它主要是针对工具构建者而不是应用程序员的.如果你只对编写应用程序感兴趣,而不想了解如何编写供其它java程序员使用的工具,那么就不要了解该机制.
java的反射机制主要提供了以下功能:
1.在运行时判断任意一个对象所属的类;
2.在运行时构造任意一个类的对象;
3.在运行时判断任意一个类所具有的成员变量和方法[通过反射机制甚至可以调用private方法];
4.在运行时调用任意一个对象的方法;
java.lang.reflect包中包括下面几个主要:
0.Class类,描述类相关信息;
1.Field类,描述类的字段;
2.Method类,描述类的方法;
3.Constructor类,描述类的构造器;
3.Array类,描述类的创建动态数组的方法,该类中所有的方法都是静态属性;
下面我们开始介绍一些具体的用法:
A.Class类:
在JAVA的Object类中声明了若干个可以在所有的JAVA类中改写的方法:
hashCode()/equals()/clone()/toString()/getClass()等,其中getClass()返回一个Class类型的对象.
Class类和一般的类一样继承自Object, 其实体用于表达JAVA程序运行时的class和interface,以及enum, array, primitive, JAVA types和关键字void,当加载一个类时,或者当加载器[class loader]的defineClass()被JVM调用,便产生一个Class对象.
Class是Reflection起源,针对任何你想查看的Class(类),必须先给该类生成一个Class的对象,然后才能通过这个对象调用相应的反射API。
JAVA提供了多种途径来为一个Class类生成对应的Class对象:
A,getClass(): Object类中的方法每个类都拥有该方法.
Example:
String str = "Test getClass()";
Class cl = str.getClass();
B,Class.getSuperclass(): Class类中的方法,返回该Class的父类的Class;
C,Class.forName()静态方法:作用同上;
D,类名.Class: 作用同上;
E,primitive wrapper classer的TYPE语法:
基本类型包装类的TYPE,Example, Integer.TYPE
PS: TYPE的使用,只适合原生[基本]数据类型.
B.运行时生成instance
要生成对象的实体,在反射机制中有两种方式:
1.针对不带参数的构造器;
Class类中的newInstance()实现该功能;
2.针对带参数的构造器;
Constructor类中的newInstance()方法,实现该功能.首先准备一个Class[]作为Constructor的参数类型.然后调用该Class对象的getConstructor()得到一个专属的Constructor对象,最后再准备一个Object[]作为Constructor对象里的newInstance()的实参.
Example:
Class c = Class.forName("DynamicTest");
Class[] pType = new Class[]{double.class, int.class};
Constructor ctor = c.getConstructor(pType);
Object[] obj = new Object[] {new Double(3.14), new Integer(119)};
Object object = ctor.newInstance(obj);
System.out.println(object);
C. 运行时调用Method:
首先必须通过Class[]作为getMethod(String name, Class[])方法的参数类型, 然后再通过Object[]存放变量,最后调用Method对象的invoke(Object obj, Object[])方法.
D.运行时调用Field内容:
修改Field不需要参数和变量, 首先调用Class的getField()方法并制定Field名称,获得特定的Field对象后便可以直接调用Field的get(Object obj)和Set(Object obj, Object value)方法.
克隆[clone]:
其实这个方法的引入,就是为了实现类似C++中深拷贝的功能.在C++中参数的传递有:传值,传地址,传引用.
在JAVA中参数传递、=的赋值操作都是"引用传递[浅拷贝]",因此为了避免误操作,在需要传值的时候就不能进行传引用.
PS:如果类成员变量有数组或者复杂成员时需要进行深度克隆.浅拷贝只复制对象本身,并不复制该对象的引用、指针等成员所指向的地址.
try{
classObj = (classObject) super.clone(); // 通常情况下,这一行代码可以实现普通的克隆.
}
catch(CloneNotSupportedException e)
{
e.printStackTrace();
}
如果classObject类中包含了String name[]成员,那么就需要进行深度克隆
try{
classObj = (classObject)super.clone();
classObj.name = (String)name.clone();
}
catch(CloneNotSupportedException e)
{
e.printStackTrace();
}
final:
一般处于设计和效率的考虑使用final,第一final类不被继承、方法不被覆盖.第二final方法会被编译器在调用final的时候转入内嵌机制大大提高执行效率.第三防止被修改;
final类不能被继承,final类不能有子类,final类中的方法默认是final类型.
final方法不能被子类的方法覆盖,但可以被继承;
final成员变量表示常量,只能赋值一次,赋值后不能再改变;
final不能修饰构造器;
PS:父类的private方法是不能被子类方法覆盖的,因为父类的private方法默认是final的;
static:
JAVA中的静态字段和方法在功能上和C++的静态字段与方法是相同的.表示属于一个类而不是属于此类的任何特定对象的变量和函数.
调用方式:
className.staticMethod();
只要这个类被加载,那么JAVA虚拟机就能根据类名在运行时的数据区的方法区内找到它们;
静态字段在内存中只有一个拷贝,JVM只为静态字段分配一次内存,在加载类的过程中完成对静态字段的内存分配;
abstract:
抽象类,具有一个或多个抽象方法的类必须被声明为abstract.通常要尽可能的把通用字段和非常抽象方法移到抽象超类中.
Object类:
Object类是JAVA中所有类的最终的祖先------每一个类都由他扩展而来.
Internal Class内部类:
内部类是定义在其它类内部的类,一般使用内部类有四个原因:
1.内部类对象能够访问创建它的对象的实现---包括那些私有数据;
2.内部类能够隐藏起来,不为同一包中的其它类所见;
3.匿名内部类可以方便的定义运行时回调;
4.使用内部类在编写事件驱动的程序时用起来很方便;
PS:
本地内部类与匿名内部类的区别在于本地内部类有构造函数,而匿名内部类只能实例初始化。
Example:
Thread thd = new Thread(
new A(){//这里就是一个匿名内部类
}
)
Proxy[代理]:
通过使用代理可以在运行时创建实现一组给定接口的新类.
代理类具有:
指定接口所要求的所有方法;
Object类定义的所有方法(toString, equals等等);
因为我们不能在运行时给这些方法定义新的代码.你必须提供一个调用处理器.调用处理器是实现了InvocationHandler接口的任意类的对象.该接口只有一个方法:
Object invoke(Object proxy, Method method, Object[] args)
只要调用了代理对象上的任意一个方法,调用处理器的invoke方法就会被调用,带着Method对象和原调用的参数.随后调用处理器必须指出如何处理调用.
要创建一个代理对象,我们必须使用proxy类中的newProxyInstance方法,该方法有三个参数:
1>类加载器.
2>一个Class对象数组,每个元素都是需要实现的接口;
3>一个调用处理器;
如何定义处理器?
对结果代理对象能做些什么?
答案要取决于我们要使用代理机制解决的问题.代理可以用于很多目的:
a.路由对远程服务器的方法调用;
b.在运行程序中把用户界面事件和动作关联起来;
c.为调试目的跟踪方法调用;
详细参见:JAVA2核心技术卷1,P225