博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java读书笔记
阅读量:5231 次
发布时间:2019-06-14

本文共 9295 字,大约阅读时间需要 30 分钟。

目录
垃圾回收机制
内存机制
继承和多态
synchronized关键字
包访问权限
遍历map
java与C++的区别
可变参数列表
java代理的实现和好处
编译时常量和final关键字
java初始化顺序
协变返回类型
初始化接口中的域
内部类链接到外部类
反射
 
内容
垃圾回收机制
1、对于垃圾回收机制来说,判断一个对象是否可回收的标准就在于该对象是否被引用
2、强引用和软引用,软引用的实现,软引用的好处。
3、虚引用有什么用?怎么用
     虚引用就是专门用来使用引用队列的一种引用,当垃圾回收器回收你的对象的时候,如果该对象被虚引用引用了,就会把虚引用放入队列。其实就是让你知道该对象被收了,仅此而已。
//创建一个字符串对象String str = new String("网络时空");//创建一个引用队列ReferenceQueue
rq = 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 Map
hm=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代理的实现和好处

实现或扩展某些功能时,一种方式是继承,但是继承的话,子类并非是真正的父类类型,更准确的说,子类包含父类,父类的所有方法都暴露在子类中(也就是说子类对象拥有所有父类的方法)。所以就可以用代理,代理是使用组合而非继承实现的,这样,使用代理的话就可以有更多的控制力,因为我们可以选择支提供在成员对象中的方法的某个子集。
编译时常量和运行时常量
编译时常量:编译器就可以把该常量值代入任何可能用到它的计算式中,也就是说,在编译时执行计算式,减轻了一些运行时的负担。在java中,这类常量必须是
基本数据类型,并且以关键字final表示,在这个常量定义的时候,必须对其进行赋值。
final修饰在数组上,数组元素的值可变,数组不可变
将方法声明为final那有两个原因,第一就是说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。第二就是允许编译器将所有对此方法的调用转化为inline调用的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。
静态的方法不具有多态性
java初始化顺序
首先,是装载.class文件,看看用到了多少个类,用到多少个类就按照先后顺序(还有继承顺序)先初始化这些类中的static修饰的成员和代码块。然后,就是执行main方法,进行对象初始化,对象初始化时先初始化父类的非static的成员和代码块,然后再是父类的构造器,接下来就是子类的非static的成员和代码块,再者是子类的构造器。
首先是父类静态块 --> 然后是子类静态块 --> 父类自由块 --> 父类构造函数块 --> 子类自由块 --> 子类构造函数块
下面这个问题,在父类中调用draw()方法,执行的是子类的draw()方法。
编写构造器时有一条有效的准则:“用尽可能简单的方法使对象进入正常状态;如果可以的话,避免调用其他方法。”能安全调用的那些方法是积累中的final方法(private方法是自动属于final方法的)
一个叫做协变返回类型的让我很困惑:
在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 }

/**

 * output
 * A
 * B
 */
初始化接口中的域:
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 }

/**

 *output:
 *true
 */
对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现。子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。
内部类链接到外部类
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 }
匿名内部类的语法相当于“创建一个继承自这个类的匿名类的对象”
相当于:
java反射
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 等都不具备的。

但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。

转载于:https://www.cnblogs.com/racing/p/3878013.html

你可能感兴趣的文章
IDEA 调试 JAVA ConcurrentLinkedQueue
查看>>
P1908-逆序对
查看>>
P1192-台阶问题
查看>>
ACM模板——康托展开
查看>>
P1025-数的划分
查看>>
P1305-新二叉树
查看>>
LGTB 与大数
查看>>
[POI2009]KAM-Pebbles
查看>>
JavaScript对象
查看>>
bzoj 3696: 化合物
查看>>
LeetCode 28. Implement strStr()
查看>>
LeetCode 15. 3Sum
查看>>
SignalR示例demo
查看>>
实验七——函数定义及调用总结
查看>>
apple-touch-startup-image 制作iphone web应用程序的启动画面
查看>>
Dp Hdu1421 搬寝室
查看>>
C/C++中的可变参函数
查看>>
最简单的二叉树
查看>>
git操作整理
查看>>
集合与深浅拷贝
查看>>