现在的位置: 首页 > 综合 > 正文

javaSE学习笔记

2017年11月27日 ⁄ 综合 ⁄ 共 9837字 ⁄ 字号 评论关闭

2012.02.29----
                EnumSet 和EnumMap
                          EnumSet.copyOf(Collection<E> c)-----将一个集合转换为EnumSet
                          EnumMap没有无参数的构造方法
                          Enum的valueOf方法将所传入的参数转换为Enum类型
        静态导入(Static import)--------------导入到类的方法名和变量名一级
                         import static com.pubstar.common.AGE(引入静态常量)--------------后面使用该变量时勿需在前面加类名
                         import static com.pubstar.common.output(引入静态方法)------------后面使用该方法时勿需在方法前面加类名
2012.03.01----
                java反射机制
                         (1) 动态语言:在运行时可以动态地改变程序结构和变量的类型(perl,python,ruby,javascript)
   (2)ava反射机制主要是通过java.lang.reflect包中的类来实现,主要的类如下:
   (3)Class类----java.lang包中,Field类-----类中的每个成员变量,Method类----类中定义的成员方法,Constructor类------类的构造方法,Array类------数组
 (4)java无论生成某个类的多少个对象,都对应于同一个Class对象
 (5)java通过反射机制动态调用一个类的方法,通过如下步骤:
1--通过Class类获取类的相关Class对象(三种方法:第一种Class.forName("类所在的包名+类名");第二种:java的内置语法--类名.class;第三种:调用类的getClass()方法) 
2--通过得到的class对象,调用class的newInstance()方法,获取该类对象对应的一个实例(返回值是一个Object对象)
3--通过类象的getMethod("方法名",方法的参数的class对象,多为Class数组),返回Method对象
4--使用Method的invoke方法,得到方法执行的结果(Object对象),invoke("第二步获取到的类的实例",具体的参数<参数个数=3中的Class数组长度>)   
(6)通过类的不带参数的构造方法,来生成对象,主要有以下两种方式
 1---先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可
 2---先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Contructor对象的newInstance()方法生成。.
(7)Integer.TYPE------返回Integer的原生数据类型(int) Integer.class--返回Integer类所对应的class对象
(8)Array.newInstance(Class<?> componentType,int...dims)中的第二个参数dims代表创建数组实例的维度。
(9)通过反射机制可以访问类内部的私有方法,这破坏了类的封装性,因为Method对象继承自AccessObject,调用其中的setAccessible(true),可以压制java的访问修饰
(10)动态代理:java.lang.reflect.InvocationHandler  java.lang.reflect.Proxy两个类
(11)java注解(Annotation):
       1---Override注解表示子类重写(override)父类的方法
       2---Deprecated注解表示不建议使用的方法
       3---SuppressWarnings注解表示抑制警告
       4---自定义注解当属性名为value时,在对其赋值时可以不指定属性的名称而直接写上属性值即可,除了value以外的其他值都需要使用name=value这种赋值方式,即明确指定给谁赋值
       5---使用@interface关键字定义一个注解时,该注解隐含地继承了java.lang.annotation.Annotation接口,当我们定义一个接口,并且让该接口继承自Annotation,我们所定义的接口依然是接口,而不是注解,Annotation本身是接口类型,而不是注解类型,对比于Enum。定义Annotation型态时,不能继承其他的Annotation型态或是接口。
       6---java.lang.annotation.Retention型态可以在定义Annotation型态时,指示编译器如何对待自定义的Annotation型态,默认编译程序会将Annotation信息留在.class档案中,但不被虚拟机读取,而仅用于编译程序或工具程序运行时提供信息。在使用Retention型态时,需要提供RetentionPolicy类型的枚举,其值主要有以下三种:CLASS,RUNTIME,SOURCE.其中CLASS说明将注解记录在.class文件当中,但不能被虚拟机获取;RUNTIME将注解记录在.class文件当中,同时也可以被虚拟机获取;SOURCE说明将注解会被编译器所抛弃,annotion只存在于源文件当中,不会被编译到class文件当中。
      7---限定Annotation使用对象@Target,使用java.lang.annotation.Target可以定义annotation的使用时机,在定义时要指定其值为java.lang.annotation.ElementType的枚举值之一,其值主要用以下几种(ANNOTATION_TYPE,CONTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PRAMETER,TYPE)。
      8---@Documented,使用者制作JavaDoc文档时也一并将Annotation的讯息加入到API文件中,使用java.lang.annotation.Documented
      9---@Inherited父类中Annotation并不会继承至子类别中,可以在定义Annotation型态时加上java.lang.anntation.Inherited型态的Annotation
(12)JUnit4的执行的一般流程:
      1----首先获得待测试类所对应的class对象
      2----通过该class对象获得当前类中所有public方法所对应的数组
      3----遍历该method数组,取得每一个method对象
      4----调用每个Method对象的isAnnotationPresent(Test.class)方法,判断该方法是否被Test注解所修饰
      5----如果该方法返回true,调用method.invoke()方法去执行该方法,否则不执行。
(13)java内部类:4种(static修饰类时只能修饰内部类)
      1----静态内部类(static inner class):只能访问内部类的静态成员变量与静态方法,生成静态内部类对象的方式为outerClass innerClass=new OuterClass.InnerClass();
      2----成员内部类(member inner class):可以访问外部类的静态与非静态的的方法与成员变量。生成成员内部类对象的方式为:OuterClass.InnerClass innerClass=(new                     OuterClass).new InnerClass();
      3----局部内部类(Locale inner class):定义在方法当中,只能访问方法当中声明的final类型的变量
      4----匿名内部类:默认继承一个类或者一个接口
(14)File类详解:
      1----构造方法:File file=new File("c:/abc/hello.txt") //目录必须存在 File file=new File("c:\\abc\\hello.txt")//不推荐使用,涉及反斜杠的转义字符的问题
      2----创建目录方法:mkdir---该方法创建目录,需创建目录的最后一级目录的父目录必须存在,否则会报错
                                          mkdirs--将需要创建的目录全部创建完成
      3----浏览目录方法:file.list()返回文件或目录的名字的字符串数组,file.listFiles()返回文件或目录的file数组
  file.list(FilenameFilter filter):返回符合过滤器的文件名,Filenamefilter只有一个方法accept
 (15)对象序列化和反序列化
      1---一个类若想序列化,需要实现java.io.Serializable接口,该接口没有定义任何方法,是一个标识性接口(Marker Interface), 当一个类实现了该接口,就表示这个类的对象              可以被 序列化。
      2---在序列化时,static变量是无法被序列化的;如果A包含B的引用,那么在序列化A时,也会将B一并序列化;如果A可以序列化,而B不可以序列化,那么当序列化A时,                  就会发生异常,这时需要将B的引用设为transient,该关键字表示变量不会被序列化。
      3---当我们在一个序列化/反序列化的类中实现了以下两个private方法(方法声明要与下面的完全保持一致),那么就允许我们以更加底层,更加细粒度的方式,控制序列化/反               序列化的过程
               private void writeObject(java.io.ObjectOutputStream out)    throws IOException

      private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;

 (16)线程
      1----概念:程序中单独顺序的流控制,线程本身不能运行,只能用于程序当中。多线程:在单个程序可以同时运行多个不同的线程,完成不同的任务。java中如果我们没   有                启动线程,系统会启动一个主线程(main方法,在主线程上运行),我们的程序都是由线程来执行的。进程:执行中的程序(程序是静态的,进程是动态的)。

      2---线程的实现:第一种方法---->继承Thread类,重写run方法;第二种方法---->实现Runnable接口,实现其run方法。将我们希望线程执行的代码放到run方法中,然后  通 过start方法来启动线程,start方法首先为线程的执行准备好系统资源,然后再去调用run方法。一个进程至少要包含一个线程。对于单核CPU来说,某一时刻只能有一个线程在执行(微观串行),从宏观角度来看,多个线程是同时执行的 (宏观并行)。对于双核或者双核以上的CPU来说,可以真正做到微观并行。
      3---Thread类实现了Runnable接口,同时也实现了run方法。
      4---当生成一个线程对象时,如果没有为其设定名字,那么线程对象的名字将使用如下形式:Thread-number, 该number将是自动增加的,并被 所有的Thread对象所共享。 (它是static的成员变量)
      5---当使用第一种方式来生成线程对象时,我们需要重写run方法,因为Thread类的run方法此时什么也不做
      6---当使用第二种方式来生成线程对象时,我们需要实现runnable接口的run方法,然后使用new Thread(new MyThread())(假如MyThread已经实现了Runnable接口)来生成线程对象,这时的线程对象的run方法就会调用MyThread类的run方法,这样我们自己编写的run方法就执行了。如果停止线程不推荐使用调用stop方法
      7---关于成员变量与局部变量:如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时,他们对该成员变量是彼此影响的(也就是说一个线程对成员变量改变会影响到另一个线程)。如果一个变量是局部变量,那么多个线程都会有一个该局部变量的拷贝,一个线程对局部变量的改变是不会影响到其他线程的。
      8---多线程同步:在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源,必须对这种潜在的资源冲突进行预防。解决方法:在线程使用一个资源时为其加锁即可。访问资源的第一个线程为其加上锁以后,其他的线程便不能再使用这个资源,除非被解锁。
             synchronized关键字:当synchronized修饰一个方法时,该方法就被称为一个同步方法
             java中的每个对象都有一个锁(lock)或者称为一个监视器(moinitor),当访问某个对象的synchronized方法时,表示将该对象上锁,此时其他任何线程都无法访问                                synchronized方法了,直到之前的那个线程执行方法完毕(或者是抛出了异常),那么将该对象的锁释放掉,其他线程才有可能去访问该 synchronized方法。 
             如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到了某个synchronized方法,那么在该方法没有执行完毕之前,其他对象无法访问该对象的任何                    synchronized方法。
             如果某个synchronized方法是static的,那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是synchornized方法所在对象所对应的class对象,                因为在java中无论一个类有多少个对象,这些对象会对应唯一个class对象。因此当线程分别访问同一个类的两个对象的两个static synchronized方法时,他们的执行顺                序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始执行。
             synchronized块写法:
             synchronized(object){
             }  表示线程在执行的时候会对object对象上锁
     synchronized方法是一种粗粒度的并发控制,某一时刻只能有一个线程执行该synchronized方法;synchronized块则是一种细粒度的并发控制,只将块中的代码同步,                位于方法内,synchronized块之外的代码是可以被多个线程所访问到的。
      9---死锁:deadlock,解决进程死锁:使用object的 wait和 notify方法,这两个方法必须要放在synchronized方法或者synchronized块中。这两个方法都是final的,会被所有的java类继承但不可以重写,这两个方法要求在调用时线程应该已经获得了对象的锁,因此这两个方法的调用需要放在synchronized方法或块中,当线程执行wait方法时,它会释放掉对象的锁。
      10--另一个会导致线程暂停的方法是Thread类的sleep方法,它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁。
      11--对于单例模式(singleton)来说,如果在getInstance()方法中生成SingleTon实例则可能会产生同步问题,即可能生成两个不同的对象。
  (17)java中对象的clone:
       1---浅复制(浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有对其他对象的引用仍然指向原来的对象,换言之浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
       2---深复制(深克隆):被复制对象的所有变量都含用与原来的对象相同的值,除去那些引用其他对象的变量,那些引用其他对象的变量将指向复制过来的新对象,而不再是原来那些被引用的对象。换言之,深复制把要复制对象的所有引用对象也复制了一遍。
       3---java 中的clone方法满足以下几方面要求:a.对任何对象x,都有x.clone()!=x;b(克隆对象与原来的对象不是一个对象).b.对任何对象而言,都有x.clone().getClass()==x.getClass()(克隆对象与原来对象的类型一样);c.如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
       4---java中对象的克隆主要遵从以下的步骤:
            a.为了获取对象的一份拷贝,我们可以利用Object类的clone()方法
            b.在派生类中发覆盖基类的clone()方法,并声明为public[Object类中的clone方法为protected]
            c.在派生类的clone()方法中,调用super.clone();(原因:在运行时刻,Object中的clone()识别出要复制的是哪个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中;继承自java.lang.Object类的clone()方法是浅复制)
            d.在派生类中实现cloneable接口(该接口与Serializable接口相同属于标记性接口)
        5--在java语言中深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象写到一个流里,再从流量读出来,就可以重建对象。这样做的前提是对象以及对象内部所有引用到的对象都 是可串行化的,否则就需要考察那些不可串行化的对象可否设定成transient,从而将之排除在复制过程之外。 
        6---如果对象序列化存到硬盘上面后,后来类的field(增加或减少或改名),当反序列化后,会出现Exception的,这样就会出现不兼容的问题,但当serialVersionUID相同时,它就会将不一样的field以及type的缺省值Deserialize这样就可以避开不兼容性的问题。
(18)java网络编程:TCP/IP-----建立socket通道,利用文件输入输出流进行操作
                                        UDP-------DatagramSocket,利用DatagramPack数据报包进行数据的传送
(19)JVM类加载器:
        1---java虚拟机在以下四种情况下结束生命周期:
            a.执行了System.exit()方法;
            b.程序正常执行结束
            c.程序在执行过程中遇到了错误或异常而异常终止;
            d.由于操作系统出现错误而导致java虚拟机进程结束。
        2---类的加载、连接与初始化
            a.加载:查找并加载类的二进制数据
            b.连接:<1>验证:确保被加载的类的正确性;<2>准备:为类的静态变量分配内存,并将其初始化为默认值;<3>解析:把类中的符号引用转化为直接引用
            c.初始化:为类的静态变量赋予正确的初始值
        3---java程序对类的使用方式可分为两种
            a.主动使用:主要包括以下六种方式----
                 <1>创建类的实例
                 <2>访问某个类或接口的静态变量,或者对该静态变量赋值
                 <3>调用类的静态方法
                 <4>反射,如Class.forName('全限定类名');
                 <5>初始化类的一个子类
                 <6>java虚拟机启动时被标明为启动类的类
            b.被动使用:除去以上六种方式,其他的均为被动使用,也不会导致类初始化。
          所有的java虚拟机实现必须在每个类或接口被java程序“首次主动使用”时才初始化他们。
       4---类的加载:主要有以下五种方式,最常用的为第一种和第三种
            a.从本地系统中直接加载;
            b.通过网络下载.class文件;
            c.从zip、jar等归档文件中加载.class文件
            d.从专有数据库中提取.class文件
            e.将java源文件动态编译为.class文件
            类的加载的最终产品就是位于堆区中的Class对象,Cass对象封装了类在方法区内的数据结构,并且向java程序员提供访问方法区内数据结构的接口。
            类加载器:<1>jvm自带的加载器:根类加载器(Bootstrap)--C++,扩展类加载器(Extension); 系统类加载器(System)后两种加载器是用java编写
                                <2>用户自定义的加载器:java.lang.ClassLoader类的子类
       5---类的验证:类文件结构的检查;语义检查;字节码验证;二进制兼容性的验证
       6---类的初始化:
            a.假如这个类没有被加载和连接,那就先进行加载和连接
            b.假如类存在直接的父类,并且这个类还没有被初始化,那么先初始化直接父类
            c.假如类中存在初始化语句,那么依次执行这些初始化语句。
          给类的编译时常量进行初始化时不会导致类的初始化---public static final int x=6/3;  
          给类的运行时常量时行初始化时会导致的初始化。---public static final int x=new Random.nextInt(100);
         
当java虚拟机初始化一个类时,要求他的父类都已经初始化,但是这条规则并不适用于接口。
         
只有当前程序访问的静态变量或静态方法确实在当前类或当前接口定义时,才可以认为是对类或接口的主动使用.
          调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。
      7--类加载器:类加载器用来把类加载到Java虚拟机中,从JDK1.2版本开始,类的加载过程采用父亲委托机制,这种机制能更好地保证java平台的安全。在此委托机制中,除
           了java虚拟机自带的根类加载器外,其余的类加载器有且只有一个父加载器。当java程序请求加载器loader1加载Sample类时,loader首先委托自己的父加载器加载
            Sample类,若父加载器能加载,则由父加载器完成加载任务。否则由加载器loader1本身加载Sample类。
          父子加载器并非继承关系,也就子加载器不一这是继承了父加载器。.
          定义类加载器:如果某个类加载器能够加载一个类,那么该类加载器称作定义类加载器,定义类加载器及其所有子加载器称作初始类加载器。
         
加载器之间的父子关系实际上指加载对象之间的包装关系,而不是类之间的继承关系。一对父子加载器可能是同一个加载器类的两个实例,也可能不是。在子加载器对象
          中包装了一个父加载器对象。
          当生成一个自定义的加载器实例时,如果没有指定它的父加载器,那么系统类加载器就将成为该类加载器的父加载器。
          同一个命名空间内的类是相互可见的
          子加载器的命名空间包含所有父加载器的命名空间。因此由子加载器加载的类能看见父加载器加载的类,例如系统加载器加载的类可以看到根类加载器加载的类
          由父类加载加载的类不能看见子加载器加载的类
  如果两个加载器之间没有直接或间接的父子关系,那么他们各自加载的类相互不可见。
 
 
 

      

    
     

      

   
     

抱歉!评论已关闭.