//创建一个字符串对象String str = new String("网络时空");//创建一个引用队列ReferenceQueuerq = new ReferenceQueue ();//创建一个虚引用,让此虚引用引用到"网络时空"字符串PhantomReference pr =new PhantomReference (str , rq);//切断str引用和"网络时空"字符串之间的引用str = null;//试图取出虚引用所引用的对象,//程序并不能通过虚引用访问被引用的对象,所以此处输出nullSystem.out.println(pr.get()); //① 输出null //强制垃圾回收System.gc();System.runFinalization();//取出引用队列中最先进入队列中引用与pr进行比较System.out.println(rq.poll() == pr); //② 输出true
Java 把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。
这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!
Java使用有向图的方式进行内存管理,可以消除引用循环的问题,例如有三个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。这种方式的优点是管理内存的精度很高,但是效率较低。另外一种常用的内存管理技术是使用计数器,例如COM模型采用计数器方式管理构件,它与有向图相比,精度行低(很难处理循环引用的问题),但执行效率很高。终于算是搞清楚了synchronized的用法(static方法前,普通方法前,代码块)
继承和多态的概念:
1 class A{ 2 3 void test1(){ 4 5 System.out.println("A:test1"); 6 7 } 8 9 void test2(){10 11 System.out.println("A:test2");12 13 }14 15 void test3(){16 17 System.out.println("A:test3");18 19 }20 21 }
1 class B extends A{ 2 3 void test1(){ 4 5 System.out.println("B:test1"); 6 7 } 8 9 void test2(){10 11 System.out.println("B:test2");12 13 }14 15 void test4(){16 17 System.out.println("B:test4");18 19 }20 21 }
1 A a=new B();2 3 a.test1();//output: B:test14 5 a.test2();//output: B:test26 7 a.test3();//output: A:test38 9 a.test4();//error: no method "test4()" exists in a
包访问权限:方法未声明时为包访问权限 eg:
继承中,若子类和父类在不同的包中,如果子类用父类new出一个指向子类的对象,该对象想调用父类的方法,则该方法可以设置为protected的
遍历Map的一种方法1 Maphm=new HashMap (); 2 3 hm.put(1,"11"); 4 5 hm.put(2,"22"); 6 7 hm.put(3,"33"); 8 9 for(Map.Entry entry:hm.entrySet())10 11 {12 13 System.out.println(entry.getKey()+":"+entry.getValue());14 15 }
java相对C++的区别:
垃圾回收器、所有对象都继承自单根基类Object和只能以一种方式创建对象(在堆上创建)
java中基本数据类型作为类的成员变量时,java确保给定其默认值,即确保是基本数据类型的成员变量得到初始化,防止产生程序错误。
数组元素中的基本数据类型值会自动初始化成空值(对于数字和字符,就是0;对于布尔型,是false)
java可变参数列表
correct:1 f(2,"s","a","e"); 2 3 f(1); 4 5 static void f(int a,String... te) 6 7 { 8 9 for(String s:te)10 11 System.out.print(s+" ");12 13 }14 15 //output: s a e
wrong:
1 f(2,'s','a','e'); 2 3 f('a','b');//compile error: ambigious 4 5 static void f(float a,Character... te) 6 7 { 8 9 for(Character s:te)10 11 System.out.print(s+" ");12 13 }14 15 static void f(Character... te)16 17 {18 19 for(Character s:te)20 21 System.out.print(s+" ");22 23 }
不希望其他任何人对一个类有访问权限,可以把所有的构造器都指定为private,从而阻止任何人创建该类的对象,但是有一个例外,在该类的static成员内部可以创建该类的对象。
在每个类中都设置一个main()方法的技术可使每个类的单元测试都变得简便可行,而且在完成单元测试之后,也无需删除main(),可以将其留待下次测试。
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass.
If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
java代理的实现和好处
实现或扩展某些功能时,一种方式是继承,但是继承的话,子类并非是真正的父类类型,更准确的说,子类包含父类,父类的所有方法都暴露在子类中(也就是说子类对象拥有所有父类的方法)。所以就可以用代理,代理是使用组合而非继承实现的,这样,使用代理的话就可以有更多的控制力,因为我们可以选择支提供在成员对象中的方法的某个子集。在Java1.4及以前,子类方法如果要覆盖超类的某个方法,必须具有完全相同的方法签名,包括返回值也必须完全一样。
Java5.0放宽了这一限制,只要子类方法与超类方法具有相同的方法签名,或者子类方法的返回值是超类方法的子类型,就可以覆盖。
注意:"协变返回(covariant return)",仅在subclass(子类)的返回类型是superclass(父类)返回类型的extension(继承)时才被容许。
1 public class A {2 public String toString()3 {4 return "A";5 }6 }
1 public class B extends A{2 3 public String toString()4 {5 return "B";6 }7 }
1 public class C{2 A process()3 {4 return new A();5 }6 }
1 public class D extends C {2 3 B process()4 {5 return new B();6 }7 }
1 public class TestABCD { 2 public static void main(String[] args) { 3 C c=new C(); 4 A a=c.process(); 5 System.out.println(a); 6 c=new D(); 7 a=c.process(); 8 System.out.println(a); 9 }10 }
/**
1 public interface C{2 Object c=0; //static final,接口中的域自动是public的3 }
1 public class D implements C {2 public static void main(String[] args)3 {4 C c=new D();5 C cc=new D();6 System.out.println(c.c==cc.c);7 }8 }
/**
1 public class D implements C { 2 int i; 3 public static void main(String[] args) 4 { 5 C c=new D(); 6 C cc=new D(); 7 System.out.println(c.c==cc.c); 8 D d=new D(); 9 InnerD id=new InnerD();//error:No enclosing instance of type D is accessible. Must qualify the allocation with an enclosing instance of type D (e.g. x.new A() where x is an instance of D).10 //InnerD id=d.createInnerD(); compile passed 或者使用 d.new InnerD();11 //如果这个内部类InnerD是static修饰的,则创建该内部类对象的时候,不需要使用D的enclosing instance来创建。12 id.printid();13 }14 public InnerD createInnerD()15 {16 return new InnerD();17 }18 private class InnerD19 {20 public void printid()21 {22 System.out.println("I'm InnerD"+" "+i);23 }24 }25 }
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Method; 3 4 public class LoadMethod { 5 public Object Load(String cName,String MethodName,String[] type,String[] param){ 6 Object retobj = null; 7 try { 8 //加载指定的Java类 9 Class cls = Class.forName(cName); 10 11 //获取指定对象的实例 12 Constructor ct = cls.getConstructor(null); 13 Object obj = ct.newInstance(null); 14 15 //构建方法参数的数据类型 16 Class partypes[] = this.getMethodClass(type); 17 18 //在指定类中获取指定的方法 19 Method meth = cls.getMethod(MethodName, partypes); 20 21 //构建方法的参数值 22 Object arglist[] = this.getMethodObject(type,param); 23 24 //调用指定的方法并获取返回值为Object类型 25 retobj= meth.invoke(obj, arglist); 26 27 } 28 catch (Throwable e) { 29 System.err.println(e); 30 } 31 return retobj; 32 } 33 34 //获取参数类型Class[]的方法 35 public Class[] getMethodClass(String[] type){ 36 Class[] cs = new Class[type.length]; 37 for (int i = 0; i < cs.length; i++) { 38 if(!type[i].trim().equals("")||type[i]!=null){ 39 if(type[i].equals("int")||type[i].equals("Integer")){ 40 cs[i]=Integer.TYPE; 41 }else if(type[i].equals("float")||type[i].equals("Float")){ 42 cs[i]=Float.TYPE; 43 }else if(type[i].equals("double")||type[i].equals("Double")){ 44 cs[i]=Double.TYPE; 45 }else if(type[i].equals("boolean")||type[i].equals("Boolean")){ 46 cs[i]=Boolean.TYPE; 47 }else{ 48 cs[i]=String.class; 49 } 50 } 51 } 52 return cs; 53 } 54 55 //获取参数Object[]的方法 56 public Object[] getMethodObject(String[] type,String[] param){ 57 Object[] obj = new Object[param.length]; 58 for (int i = 0; i < obj.length; i++) { 59 if(!param[i].trim().equals("")||param[i]!=null){ 60 if(type[i].equals("int")||type[i].equals("Integer")){ 61 obj[i]= new Integer(param[i]); 62 }else if(type[i].equals("float")||type[i].equals("Float")){ 63 obj[i]= new Float(param[i]); 64 }else if(type[i].equals("double")||type[i].equals("Double")){ 65 obj[i]= new Double(param[i]); 66 }else if(type[i].equals("boolean")||type[i].equals("Boolean")){ 67 obj[i]=new Boolean(param[i]); 68 }else{ 69 obj[i] = param[i]; 70 } 71 } 72 } 73 return obj; 74 } 75 }
Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。
但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。