基本类型

  • byte 8位整数,-128~127
  • short 16位整数,-32768~32767
  • int 32位
  • long 64位,为了标识,建议跟个后缀L或l。
  • float 32位浮点小数,有一个后缀F/f,没有后缀的浮点数默认为double类型。
  • double 64位浮点小数,后缀D/d。
  • char 字符型
  • boolean 布尔型

  • 只有很少的情况适用float,例如,需要快速地处理单精度数据,或者需要存储海量数据。否则都是使用double。

  • Java整型和浮点数都是有符号数,不存在有符号数和无符号数比较或运算时出错的情况。

限定符

  • 对类、接口及其成员进行声明时,public表示可以被任何人访问
  • protected只能被本包的本类和位于任何包的子类访问
  • default只能被本包访问
  • private只能被本类访问
  • 重载可以改变方法的访问范围,但只能变大。

final

  • 一个final类不能有子类,一个final的field表示它是一个常量。
  • 一个final域需要在对象调用构造器后就被初始化,不接受默认初始化,因此定义了final常量后要么顺便赋个值给它,要么在构造器里给它赋值。
  • 把方法的入参定义为final的话,该参数不可以被重新赋值。可以防止在方法里面不小心改变了不能变的参数,造成一些不必要的麻烦。

     public static void printAll(final Curry temp){ //实参传进来给形参,就相当于初始化完成
        temp.setSmallName("fk do it");
        System.out.println(temp.getSmallName());
        temp = new Curry(); 传送进来的Curry引用是final,不可以再赋值了,这里一定会报错哦!
    
    }
    

static

  • 一个static的field表明它是属于类的,而不是每一个对象都单独拥有一份的。
  • 类加载的时候将static变量初始化(接受默认初始化)并加载到方法区,因此它是随着类的加载而加载的
  • 一个static的final常量由于不能被默认初始化,所以类加载的时候若它还未人为初始化则编译报错。因此静态常量需要定义即赋值或在静态代码块中赋值(构造器不随类加载而执行,而是随着对象创建而被调用的),或者像笔记:hibernate学习之Crud->封装Util获取session工厂一样,让final常量=一个静态方法的返回值,强制类加载时也把静态方法执行了。反正必须让它在类加载时完成初始化。
  • 静态方法则不会随着类的加载而执行,但静态代码块是随着项目的开始而执行的。

    native

  • native修饰某个方法表明该方法实现的文件是由其他语言(C/C++等)写的。

Array.length

  • 数组的求长度(总容量)属性length是java.lang.reflect.Array中的一个属性,该属性由getLength(Object array)方法赋值,但这个方法是由其他语言来实现的,因为要接触到底层,而java语言本身是不接触 及其底层的。

    数组

  • 声明一个父类数组,其中可以放子类对象,但是这些对象就被隐转成父类,只有父类的成员了。
  • 用instanceof能检测出元素的原类型
  • 定义基本类型数组,声明后即可放入元素

    int[] a=new int[5];
    a[0]=0;
    
  • 定义元素为类的数组,声明后还要对每个元素都new一遍,否则元素全部为空指针

    Bag<Integer>[] adj=(Bag<Integer>[])new Bag[V]; //不能创建泛型指定类型的泛型数组,只能先创建泛型数组再强转
    //这一步不能省略,必须一个个分配Bag,否则adj数组中每个元素都是空指针
    for(int i=0;i<V;i++){
        adj[i]=new Bag<Integer>();
        adj[i].add(i); //不经过上一行的话报空指针异常
    }
    

    父类强转为子类

  • 可以的,但此父类对象必须原本就是由子类对象转来的。
  • 例如,Father father=new Son()或Father father=(Father)son;
  • 转换前可以先用instanceof检查

    if(father instanceof Son){
        Son son=(Son)father;
    }
    
  • 其实子类转为父类(隐式或强制),比父类多的成员只是暂时不能访问,被隐藏了而已,被转回来之后又能访问了。

构造方法不能继承

  • 如果父类中有无参构造函数,创建子类时,必须在构造函数第一行调用父类的无参构造函数;如果父类只定义了有参构造函数,那么编译器无法隐式加上无参构造函数,而子类又需要调用无参构造函数,故编译报错。当然,如果子类需要的只是父类的有参构造函数,那么调用即可。编译器不会因为父类缺少无参构造函数而报错。

同父类强转在编辑时检测不到异常

  • 编译时才能发现类型不能强制的错误,并且抛异常,所以不要以为强转时没飘红就是可以了,只是检测不出来而已。

collection.toArray()

  • list.toArray(): 将list(或其他集合如Set)转为Object[]。
String[] array= (String[]) list.toArray();
  • 以上代码运行报错:Exception in thread “main” java.lang.ClassCastException:
    [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;原因是不能将Object[]直接转为String[],只能遍历每一个元素进行转化。
  • Java中的强制类型转换只针对单个对象,不能将整个数组转换为另一类型,这和数组初始化时需要一个个来是类似的。
  • 正解:
Object[] arr = list.toArray();
for (int i = 0; i < arr.length; i++) {
    String e = (String) arr[i];
}
  • list.toArray(T[] a): 转化为指定类型数组,比上个方法更好用。
predicates.toArray(new Predicate[0]); // toArray(数组):将调用方法的对象转换为数组,
                                   // 并存储到传入的数组中;若数组空间不足则重新创造一个数组并返回
predicates.toArray( new Predicate[predicates.size()] );                                

线程

  • synchronized:Java 关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

    //该方法是产生一个double型的Gaussian随机数
    public synchronized double nextGaussian(){
    
    }
    

获取当前类名

  • this.getClass().getName()
  • Thread.currentThread().getStackTrace()[1].getClassName()

    System.currentTimeMillis()获取当前时间

  • 获取当前的时间,new Date()底层调用的也是这个

    long startTime= System.currentTimeMillis();//返回一个long型,保存到数据库转为date展示(Date原本也是用秒数表示的)
    

获取文件后缀名

File file = new File("HelloWorld.java");
String fileName = file.getName();
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);

测试程序运行时间

  • 在程序开始前记录一次当前时间,程序结束时再记录一次,两者相减即可

    long startTime = System.currentTimeMillis();
    ---待测试程序---
    long endTime = System.currentTimeMillis();
    System.out.println("运行时间:" + (endTime - startTime) + "ms");
    

System.nanoTime()

  • 返回纳秒(即当前与某个时间基准的时间差),1ms=1ns10001000,中间还隔了个微秒。

    long time1=System.nanoTime();
    
  • 只用于计算时间差,不要用于计算距离现在的时间差,因为纳秒太小了

    //计算程序运行时间
    long time1=System.nanoTime();
    for(int i=0;i<200;i++){
        System.out.print(".");
    }
    long time2=System.nanoTime();
    System.out.println(time2-time1);
    

参数类型后加…

  • test(ObjectA… objectAs)可变长度参数列表,表示这个类型的入参可以有0个或多个ObjectA或ObjectA[],传参时可以是一个个并列地传,也可以是直接一个数组。
  • 方法内对它们的遍历:

    public void correlationRoles(Long... roleIds) {
        for(Long roleId : roleIds) {
    
        }
    
        //or
        for(int i=0;i<roleIds.length;i++){  
    
        }
    }
    
  • 如果调用时什么也没传,那么该参数的长度为0。

  • 必须放在最后一个形参的位置上,否则报错。
  • 假如已有一个方法test(String… strings),那么还可以写方法test(),而当我们调用test()时,编译器优先匹配test()方法,没有test()时才会匹配test(String… strings);
  • 但是不能写test(String[] strings),编译出错,系统提示出现重复方法。

Clazz

  • 为什么很多程序员喜欢用Clazz命名?
  • 它表示类的意思,因为Class已经被作为关键字,人们不能再使用,因此用clazz作为代替。

Deque类

  • 即double ended queue,双端队列,继承自Queue,是一种具有队列和栈的性质的数据结构。元素可以从两端弹出,插入和删除都可以在两端进行。
  • push(): 向队头插入元素。
  • pop(): 弹出队头元素。
  • removeFirst(): 弹出首元素,如果是作为栈来使用则应该是最后一个进去的元素。
  • removeLast(): 弹出尾元素。
  • 参考文章
  • 代码示例:ideaProjects/shiro-chapter18/web/shiro/filterKickoutSessionControllerFilter;不知道为什么在这里removeFirst()弹出的是队尾元素,removeLast()反而是队头。

StringUtils

  • hasText(str): 字符串判空,如果字符串为null、””或” “,那么返回false。