java基础知识11-java运行时
2013-12-22 16:56
597 查看
1:java寻找类
当我们初始化一个类的实例的时候,java虚拟机会查找并且加载这个类。当然用Class.forName("xxx"),用来查找和加载一个类,返回一个句柄来控制这个类的其他操作,比如产生一个实例。
2:判断对象是否是类的实例
方法一:
TestClass x = new TestClass();
if( x instanceof TestClass)
方法二:
if(TestClass.class.isInstance(x))
毫无疑问方法2是一种优势,可以避免修改代码
3:类Class
public final class Class<T>
extends Object
implements Serializable, GenericDeclaration, Type, AnnotatedElement
之前用到的Class.forName("xx"); 其中的Class就是一个类,很奇怪吧,Class的实例表示正在运行的类或者接口。Class没有公共构造函数,Class的对象是被java虚拟机自动的构造当类被加载并且调用。
java 中并不是一开始就加载所有的类,而是用到什么就加载什么,所以一个类在第一次调用时时候会产生这个类的Class 对象,记住是Class对象,而不是类的实例,当我们再次实例化这个类的时候,用的就是这个Class的object。
结果:
class Cookie
class Cookie
true
例子2:
从这个例子可以看出我们可以利用Class类来知道类的祖宗十八代的信息。
4:类的标记
Class X{};
X.class代表的就是Class的object。
5:java的反射机制
java的反射机制就是在运行时获取一个类的各种信息,包括字段,函数,构造函数。可对一个编译期完全未知的对象进行实际的设置以及发出方法调用。
6:java 函数参数的传递
java中函数中传递的是句柄,在函数内部对句柄是复制的,但是即便复制了句柄,不同的句柄所指向的内存还是一样的,所以这个时候就相当于C++ 的传引用调用,这个时候传递参数的话,那么就会对函数外部的对象产生一些额外的影响。
7:java的clone
为了解决参数句柄传递时发生的类似C++中的传引用的副作用,我们引入了对象的Clone概念。所谓的对象Clone就是把对象完全复制,然后只针对这个对象进行操作。Clone是Object类的protected函数
protected Object clone()throws CloneNotSupportException
因此要在类的外部调用clone函数,必须重载Object的clone函数,并且将其设为public函数,并且在重载的时候要注意调用super.clone().
其次就是实现java.lang 中的Cloneable接口,这个接口是奇怪的,因为它是空的,interface Cloneable{},我们实现它,其实就可以在原理上利用 if myHanble instanceof Cloneable,这样的判断,去判断一个类是否可以被clone。
8:clone中的浅clone 和深 clone
当我们进行clone的时候,如果对象中包含类对象,那么在进行clone的时候,一定要记得将成员类实例进行clone。例如下面的例子:
运行结果如下所示:
s1 is::a:b:c:d:e
s2 is::a:b:c:d:e
Now after s1 increace s2 is::a:c:d:e:f
从以上运行结构可以看出,我们的clone函数仅仅clone了Snake对象的第一个部分,所以s1运行increament后,s2的只有第一节a不变,后面的节数还是跟随着s1的变化产生了变化,所以进行clone的时候一定要注意其他类实例成员的clone,现在修改clone函数,如下所示:
通过上面的代码的修改,程序的运行结果如下所示:
s1 is::a:b:c:d:e
s2 is::a:b:c:d:e
Now after s1 increace s2 is::a:b:c:d:e
可以看到s2没有随着s1的变换而发生变化,从而达到了我们的预期目标。
9:继承类的clone
当一个继承类的父类有可以调用的clone函数时候我,我们并不需要重新改写clone函数即便我们在继承函数中增加了新的字段,这是因为Object.clone会自动识别是继承类调用的clone函数,那么就会自动复制继承类中新增加的字段。如下程序所示:
结果:
x3.j = 7x4.j = 7
说明继承类Int3中自动完成了新增加字段j的复制,即便Int3中,没有改写父类Int2的clone函数
10:clone 和对象的序列化
java对象序列化就是把对象在内存中的状态转变成字节序列保存起来,反序列化就是把对象从保存的字节中恢复出来,通过Inputstream,OutputStream,ObjectInputStream,ObjectInputStream流对象来操作。
其实对象的反序列化经历的就是一个clone的过程,但是它用的 时间比clone长并且不稳定。
11:clone的关闭
当一个类具有clone功能的时候,其子类都会继承这种clone功能,但是有时候处于安全我们想关闭clone功能时,可以采用一些方法:
重新改写clone,使其为空;
使clone抛出CloneNotSupportedException等方法
12:关于java的复制构造函数,java的复制构造函数,thinking in java的作者用了这样的一个例子来说明,但是感觉说的太模糊了,总体上我认为java不适合采用复制构造函数的原因有:
java中包含多个类成员的时候,复制构造函数需要调用每个类的复制构造函数,这个是比较麻烦的;
java中传递的是句柄,当把子对象的句柄传入父级时,会造成切片问题,丢失子类信息,但是这个在C++中也是存在的,所以这个不是java不要用复制构造函数的理由
C++中的复制构造函数时C++自身机制的一部分(即便我们没用写复制构造函数,系统也会为我们生成一个),所以我们可以方便的调用复制构造函数去创建本地对象的一个副本(传值调用+其他类的复制构造函数),但是java中对象都是用句柄表示,不能通过简单的赋值来解决问题。
当我们初始化一个类的实例的时候,java虚拟机会查找并且加载这个类。当然用Class.forName("xxx"),用来查找和加载一个类,返回一个句柄来控制这个类的其他操作,比如产生一个实例。
try{ Class x = Class.forName("xx"); Object y = x.newInstance(); //newInstance 返回Object句柄,并且类的构造函数必须没有任何参数 }catch(InstantiationException e) { }catch(IllegalAccessException e) { } catch(ClassNotFoundException e) { e.printStackTrace(); }
2:判断对象是否是类的实例
方法一:
TestClass x = new TestClass();
if( x instanceof TestClass)
方法二:
if(TestClass.class.isInstance(x))
毫无疑问方法2是一种优势,可以避免修改代码
3:类Class
public final class Class<T>
extends Object
implements Serializable, GenericDeclaration, Type, AnnotatedElement
之前用到的Class.forName("xx"); 其中的Class就是一个类,很奇怪吧,Class的实例表示正在运行的类或者接口。Class没有公共构造函数,Class的对象是被java虚拟机自动的构造当类被加载并且调用。
java 中并不是一开始就加载所有的类,而是用到什么就加载什么,所以一个类在第一次调用时时候会产生这个类的Class 对象,记住是Class对象,而不是类的实例,当我们再次实例化这个类的时候,用的就是这个Class的object。
Class x =Class.forName("Cookie"); Object yy = x.newInstance(); System.out.println("the class name is:"+x.getName()); Class z = Cookie.class; System.out.println(x); System.out.println(z); System.out.println( x == z);
结果:
class Cookie
class Cookie
true
例子2:
class TestX {} interface faceX {} interface faceY {} class TestY extends TestX implements faceX,faceY {} public class ClassAndInterface { public static void main(String[] args) { Class Obj = null; try { Obj = Class.forName("TestY"); }catch(ClassNotFoundException e) { e.printStackTrace(); } Class[] faces = Obj.getInterfaces(); for(int i =0;i<faces.length;i++) System.out.println(faces[i]); Class cf = Obj.getSuperclass(); Object Osu = null; try{ Osu = cf.newInstance(); }catch(InstantiationException ie) { }catch(IllegalAccessException ie) {} System.out.println(Osu); } }
从这个例子可以看出我们可以利用Class类来知道类的祖宗十八代的信息。
4:类的标记
Class X{};
X.class代表的就是Class的object。
5:java的反射机制
java的反射机制就是在运行时获取一个类的各种信息,包括字段,函数,构造函数。可对一个编译期完全未知的对象进行实际的设置以及发出方法调用。
6:java 函数参数的传递
java中函数中传递的是句柄,在函数内部对句柄是复制的,但是即便复制了句柄,不同的句柄所指向的内存还是一样的,所以这个时候就相当于C++ 的传引用调用,这个时候传递参数的话,那么就会对函数外部的对象产生一些额外的影响。
public class CObject { int i; CObject(int i) { this.i = i; } public static void main(String[] args) { CObject x = new CObject(2); CObject y = x; x.i++; System.out.println("X's i ="+x.i); System.out.println("Y's i ="+y.i); System.out.println(x); System.out.println(y); } }
7:java的clone
为了解决参数句柄传递时发生的类似C++中的传引用的副作用,我们引入了对象的Clone概念。所谓的对象Clone就是把对象完全复制,然后只针对这个对象进行操作。Clone是Object类的protected函数
protected Object clone()throws CloneNotSupportException
因此要在类的外部调用clone函数,必须重载Object的clone函数,并且将其设为public函数,并且在重载的时候要注意调用super.clone().
其次就是实现java.lang 中的Cloneable接口,这个接口是奇怪的,因为它是空的,interface Cloneable{},我们实现它,其实就可以在原理上利用 if myHanble instanceof Cloneable,这样的判断,去判断一个类是否可以被clone。
8:clone中的浅clone 和深 clone
当我们进行clone的时候,如果对象中包含类对象,那么在进行clone的时候,一定要记得将成员类实例进行clone。例如下面的例子:
public class Snake implements Cloneable{ private Snake next; private char c; Snake(int i,char x) { c = x; if(--i > 0) next = new Snake( i,(char)(x+1) ); } void increment() { c++; if(next != null) next.increment(); } public String toString() { String s = ":" + c; if(next!=null) s += next.toString(); return s; } public Object clone() { Object Obj = null; try { Obj = super.clone(); }catch(CloneNotSupportedException ce) { System.out.println("Cann't clone this object"); } return Obj; } public static void main(String[] args) { Snake s1 = new Snake(5,'a'); System.out.println("s1 is:" + s1); Snake s2 = (Snake)s1.clone(); System.out.println("s2 is:" + s2); s1.increment(); System.out.println("Now after s1 increace s2 is:" + s2); } }
运行结果如下所示:
s1 is::a:b:c:d:e
s2 is::a:b:c:d:e
Now after s1 increace s2 is::a:c:d:e:f
从以上运行结构可以看出,我们的clone函数仅仅clone了Snake对象的第一个部分,所以s1运行increament后,s2的只有第一节a不变,后面的节数还是跟随着s1的变化产生了变化,所以进行clone的时候一定要注意其他类实例成员的clone,现在修改clone函数,如下所示:
public Object clone() { Snake Obj = null; try { Obj = (Snake)super.clone(); if(Obj.next != null) Obj.next = (Snake)Obj.next.clone(); }catch(CloneNotSupportedException ce) { System.out.println("doesn't support clone"); } return Obj; }
通过上面的代码的修改,程序的运行结果如下所示:
s1 is::a:b:c:d:e
s2 is::a:b:c:d:e
Now after s1 increace s2 is::a:b:c:d:e
可以看到s2没有随着s1的变换而发生变化,从而达到了我们的预期目标。
9:继承类的clone
当一个继承类的父类有可以调用的clone函数时候我,我们并不需要重新改写clone函数即便我们在继承函数中增加了新的字段,这是因为Object.clone会自动识别是继承类调用的clone函数,那么就会自动复制继承类中新增加的字段。如下程序所示:
import java.util.*; class Int2 implements Cloneable { private int i; public Int2(int ii) { i = ii; } public void increment() { i++; } public String toString() { return Integer.toString(i); } public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) { System.out.println("Int2 can't clone"); } return o; } } class Int3 extends Int2 { private int j; // Automatically duplicated public Int3(int i) { super(i); } public Int3(int i,int j){super(i);this.j = j;} public String toString() { return Integer.toString(j); } } public class AddingClone { public static void main(String[] args) { Int3 x3 = new Int3(1,7); Int3 x4 = (Int3)x3.clone(); System.out.println("x3.j = "+x3 +"x4.j = "+x4); } }
结果:
x3.j = 7x4.j = 7
说明继承类Int3中自动完成了新增加字段j的复制,即便Int3中,没有改写父类Int2的clone函数
10:clone 和对象的序列化
java对象序列化就是把对象在内存中的状态转变成字节序列保存起来,反序列化就是把对象从保存的字节中恢复出来,通过Inputstream,OutputStream,ObjectInputStream,ObjectInputStream流对象来操作。
其实对象的反序列化经历的就是一个clone的过程,但是它用的 时间比clone长并且不稳定。
11:clone的关闭
当一个类具有clone功能的时候,其子类都会继承这种clone功能,但是有时候处于安全我们想关闭clone功能时,可以采用一些方法:
重新改写clone,使其为空;
使clone抛出CloneNotSupportedException等方法
12:关于java的复制构造函数,java的复制构造函数,thinking in java的作者用了这样的一个例子来说明,但是感觉说的太模糊了,总体上我认为java不适合采用复制构造函数的原因有:
java中包含多个类成员的时候,复制构造函数需要调用每个类的复制构造函数,这个是比较麻烦的;
java中传递的是句柄,当把子对象的句柄传入父级时,会造成切片问题,丢失子类信息,但是这个在C++中也是存在的,所以这个不是java不要用复制构造函数的理由
C++中的复制构造函数时C++自身机制的一部分(即便我们没用写复制构造函数,系统也会为我们生成一个),所以我们可以方便的调用复制构造函数去创建本地对象的一个副本(传值调用+其他类的复制构造函数),但是java中对象都是用句柄表示,不能通过简单的赋值来解决问题。
相关文章推荐
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- XP下使用虚拟机安装配置Solaris[多图]
- [原创]java局域网聊天系统
- java很神奇 用swing制作欢迎屏幕
- java自动生成验证码插件-kaptcha
- VirtualBox虚拟机XP与宿主机Ubuntu互访共享文件夹
- ITeye上“10个人,8个人不会解释这个问题”的帖子
- Java IO与NIO的一些文件拷贝测试
- Java反射随记
- Java简单字符串插值实现
- String.intern