JAVA学习

Java关键字50个深度解析

2018-06-06  本文已影响35人  Fitz_Lee

Java关键字列表如下,包含50个关键,所有字符都是小写
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html

image.png

基本类型

先介绍基本类型关键字如下

image.png
有关基本类型的解释,主要是整形byte/short/int/long,浮点float/double,字符型char, 布尔值boolean,参考解释https://blog.csdn.net/qwe969153746/article/details/53353534

注意:Java浮点数默认是double, 整形默认是int,另外有一个常量池的缓存也需要注意,还有Integer.valueof()方法是Integer a = 10语句的默认赋值方法。

/**
 * 8种基本类型的包装类和对象池
 *      包装类:java提供的为原始数据类型的封装类,如:int(基本数据类型),Integer封装类。
 *      对象池:为了一定程度上减少频繁创建对象,将一些对象保存到一个"容器"中。
 * 
 *  Byte,Short,Integer,Long,Character。这5种整型的包装类的对象池范围在-128~127之间,也就是说,
 *  超出这个范围的对象都会开辟自己的堆内存。
 * 
 *  Boolean也实现了对象池技术。Double,Float两种浮点数类型的包装类则没有实现。
 *  String也实现了常量池技术。
 * 
 * 自动装箱拆箱技术
 *  JDK5.0及之后允许直接将基本数据类型的数据直接赋值给其对应地包装类。
 *  如:Integer i = 3;(这就是自动装箱)
 *  实际编译代码是:Integer i=Integer.valueOf(3); 编译器自动转换
 *  自动拆箱则与装箱相反:int i = (Integer)5;
 */
public class Test {
    public static void main(String[] args) {
        
        //基本数据类型常量池范围-128~127
        Integer n1 = -129;
        Integer n2 = -129;
        Long n3 = 100L;
        Long n4 = 100L;
        Double n5 =  12.0;
        Double n6 = 12.0;
        //false
        System.out.println(n1 == n2);
        //true
        System.out.println(n3 == n4);
        //false
        System.out.println(n5 == n6);
        
        //String常量池技术,注意:这里String不是用new创建的对象
        String str1 = "abcd";
        String str2 = "abcd";
        //true
        System.out.println(str1 == str2);
                

    }
}

   //5种整形的包装类Byte,Short,Integer,Long,Character的对象,

   //在值小于127时可以使用常量池

   Integer i1=127;

   Integer i2=127;

   System.out.println(i1==i2)//输出true

   //值大于127时,不会从常量池中取对象

   Integer i3=128;

   Integer i4=128;

   System.out.println(i3==i4)//输出false

   //Boolean类也实现了常量池技术

   Boolean bool1=true;

   Boolean bool2=true;

   System.out.println(bool1==bool2);//输出true

   //浮点类型的包装类没有实现常量池技术

   Double d1=1.0;

   Double d2=1.0;

   System.out.println(d1==d2)//输出false

以下是条件分支和循环语句关键字

以下是异常处理机制

image

try catch jvm原理:
https://blog.csdn.net/TellH/article/details/70940757#t0

package test;  
//jdk 1.8  
public class TestException1 {  
  
      
    /** 
     * catch中的return和throw是不能共存的(无论谁先谁后都编译不通过) 
     * 如果只throw e,则必须try-catch捕捉异常e或用throws抛出异常e 
     * 如果只return ,则在catch段正常返回值 
     */  
    int testEx0(){  
        boolean ret = true;  
        try {  
            int c = 12 / 0;  
            System.out.println("testEx,successfully");  
            return 0;  
        } catch (Exception e) {  
            System.out.println("testEx, catch exception");  
            ret = false;  
            return -1;  
            throw e;  
        }  
    }  
    /** 
     * 在finally中的return和throw是不能共存的(无论谁先谁后都编译不通过) 
     * 如果只throw e,则必须try-catch捕捉异常e或用throws抛出异常e 
     * 如果只return ,则在catch段正常返回值 
     */  
    int testEx00(){  
        int  ret = 0;  
        try {  
            int c = 12 / 0;  
            System.out.println("testEx,successfully");  
            return ret;  
        } catch (Exception e) {  
            System.out.println("testEx, catch exception");  
            ret = -1;  
        }finally{  
            ret = 1;  
            System.out.println("testEx, finally; return value=" + ret);  
            throw e;  
            return ret;  
        }  
    }  
    /** 
     * 结果: 
        testEx, catch exception 
        testEx, finally; return value=false 
        false 
        结论:在finally里没有return的时候:先执行finally的语句,再执行catch的return 
     */  
    boolean testEx01(){  
        boolean ret = true;  
        try {  
            int c = 12 / 0;  
            System.out.println("testEx,successfully");  
            return true;  
        } catch (Exception e) {  
            System.out.println("testEx, catch exception");  
            ret = false;  
            return ret;  
        }finally{  
            System.out.println("testEx, finally; return value=" + ret);  
              
        }  
    }  
    /** 
     *  结果: 
     *  testEx, catch exception 
        testEx, finally; return value=1 
        1 
        结论:在finally里有return的时候:先执行finally的语句和return,忽略catch的return 
     */  
    int testEx02(){  
        int ret = 0;  
        try {  
            int c = 12 / 0;  
            System.out.println("testEx,successfully");  
            return ret;  
        } catch (Exception e) {  
            ret = -1;  
            System.out.println("testEx, catch exception");  
            return ret;  
        }finally{  
            ret = 1;  
            System.out.println("testEx, finally; return value=" + ret);  
            return ret;  
        }  
    }  
    /** 
     * 编译能通过, 
     * 但运行时抛异常(当然也没有返回值) 
     * @return 
     */  
    boolean testEx03(){  
        boolean ret = true;  
        try {  
            int c = 12 / 0;  
            System.out.println("testEx,successfully");  
            return true;  
        } catch (Exception e) {  
            System.out.println("testEx, catch exception");  
            ret = false;  
            throw e;  
        }finally{  
            System.out.println("testEx, finally; return value=" + ret);  
              
        }  
    }  
    /** 
     * 编译不能通过(必须加throws主动抛异常,或try-catch捕捉,) 
     * 但运行时抛异常(当然也没有返回值) 
     * @return 
     * @throws Exception  
     */  
    boolean testEx031(){  
        boolean ret = true;  
        try {  
            int c = 12 / 0;  
            System.out.println("testEx,successfully");  
            return true;  
        } catch (Exception e) {  
            System.out.println("testEx, catch exception");  
            ret = false;  
            throw new Exception(e);  
        }finally{  
            System.out.println("testEx, finally; return value=" + ret);  
              
        }  
    }  
    /** 
     * 结果: 
     *  testEx, catch exception 
        testEx, finally; return value=1 
        1  
        结论: 
        函数在finally里正常返回return的值,无异常,显然catch中的throw被忽略 
     */  
    int testEx04(){  
        int ret = 0;  
        try {  
            int c = 12 / 0;  
            System.out.println("testEx,successfully");  
            return ret;  
        } catch (Exception e) {  
            System.out.println("testEx, catch exception");  
            ret = -1;  
            throw e;  
        }finally{  
            ret = 1;  
            System.out.println("testEx, finally; return value=" + ret);  
            return ret;  
        }  
    }  
      
    public static void main(String[] args) {  
        try {  
            System.out.println(new TestException1().testEx0());  
            //System.out.println(new TestException1().testEx00());  
            //System.out.println(new TestException1().testEx01());  
            //System.out.println(new TestException1().testEx02());  
            //System.out.println(new TestException1().testEx03());  
            //System.out.println(new TestException1().testEx031());  
            //System.out.println(new TestException1().testEx04());  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}  

以下是类或这变量的权限控制

image.png

以下修饰字段变量的关键字

image.png

synchronized同步控制


简单来说原理是
  1. synchronized修饰对象或类
    重量级锁也就是通常说synchronized的对象锁,锁标识位为10,其中指针指向的是monitor对象(在 Synchronized 代码块中的监视器 )的起始地址。每个对象都存在着一个 monitor 与之关联,对象与其 monitor 之间的关系有存在多种实现方式,如 monitor 可以与对象一起创建销毁或当线程试图获取对象锁时自动生成,但当一个 monitor 被某个线程持有后,它便处于锁定状态。 有monitorenter和monitorexit的操作

  2. synchronized修饰方法
    当方法调用时,调用指令将会 检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先持有 monitor , 然后再执行方法,最后再方法完成(无论是正常完成还是非正常完成)时释放monitor


    image.png
image.png
  1. 轻量级锁和重量级锁
    轻量级锁。他的基本思想是,当线程要获取锁时把锁对象的 Mark Word 复制一份到当前线程的栈顶,然后执行一个 CAS 操作把锁对象的 Mark Word 更新为指向栈顶的副本的指针,如果成功则当前线程拥有了锁。
    偏向锁。获取的过程如下,当锁对象第一次被线程获取的时候,虚拟机把对象头中的标志位设为“01”,即偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word之中的偏向线程ID,并将是否偏向锁的状态位置置为1。如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,直接检查ThreadId是否和自身线程Id一致,如果一致,则认为当前线程已经获取了锁,虚拟机就可以不再进行任何同步操作(例如Locking、Unlocking及对Mark Word的Update等)。
    详见原理: https://www.jianshu.com/p/ce4f5e43e0a8?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=weixin

其他关键字

前面对jvm 的vtable 进行了研究和验证,再总结下特点:

  1. vtable 分配在 instanceKlass对象实例的内存末尾 。
  2. 其实vtable可以看作是一个数组,数组中的每一项成员元素都是一个指针,指针指向 Java 方法在 JVM 内部所对应的 method 实例对象的内存首地址 。
  3. vtable是 Java 实现面向对象的多态性的机制,如果一个 Java 方法可以被继承和重写, 则最终通过 put_method_at函数将方法地址替换,完成 Java 方法的动态绑定。
    4.Java 子类会继承父类的 vtable,Java 中所有类都继承自 java.lang.Object, java .lang.Object 中有 5 个虚方法(可被继承和重写):
    void finalize()
    boolean equals(Object)
    String toString()
    int hashCode()
    Object clone()
    因此,如果一个 Java 类中不声明任何方法,则其 vtalbe 的长度默认为 5 。
    5.Java 类中不是每一个 Java 方法的内存地址都会保存到 vtable 表中,只有当 Java子类中声明的 Java 方法是 public 或者 protected 的,且没有 final 、 static 修饰,并且 Java 子类中的方法并非对父类方法的重写时, JVM 才会在 vtable 表中为该方法增加一个引用 。
    6.如果 Java 子类某个方法重写了父类方法,则子类的vtable 中原本对父类方法的指针会被替换成子类对应的方法指针,调用put_method_at函数替换vtable中对应的方法指针。
image

</figure>

1、obj如果为null,则返回false;否则设S为obj的类型对象,剩下的问题就是检查S是否为T的子类型;

2、如果S == T,则返回true;

3、接下来分为3种情况,之所以要分情况是因为instanceof要做的是“子类型检查”,而Java语言的类型系统里数组类型、接口类型与普通类类型三者的子类型规定都不一样,必须分开来讨论。

①、S是数组类型:如果 T 是一个类类型,那么T必须是Object;如果 T 是接口类型,那么 T 必须是由数组实现的接口之一;

②、接口类型:对接口类型的 instanceof 就直接遍历S里记录的它所实现的接口,看有没有跟T一致的;

③、类类型:对类类型的 instanceof 则是遍历S的super链(继承链)一直到Object,看有没有跟T一致的。遍历类的super链意味着这个算法的性能会受类的继承深度的影响。

上一篇 下一篇

猜你喜欢

热点阅读