基本语法

comparable 和 Comparator 的区别

  • comparable 接口实际上是出自java.lang包 它有一个 compareTo(Object obj)方法用来排序
  • comparator接口实际上是出自java.util包它有一个compare(Object obj1, Object obj2)方法用来排序

需要对一个集合使用自定义排序时,就要重写compareTo()方法或compare()方法

赋值

JAVA的赋值运算是有返回值的,赋了什么值,就返回什么值

Boolean flag = false;
if (flag = true)
{
    System.out.println("true");
}
else
{
    System.out.println("false");
}

输出true

++ii++

无论是i++++i,对于 i 变量本身来说没有任何区别,执行的结果都是i变量的值加1,关键在于和=的结合

        int i = 1;
        i++;
        ++i;
        System.out.println("i=" + i);//i=3
        int j = i++;
        System.out.println("j=" + j);//先将i赋值给j,再将i自增.i=4,j=3
        int m = ++i;
        System.out.println("m=" + m);//先将i自增,再将自增后的值赋给m,m=5,i=5
        System.out.println(m++);//先打印m后将m自增,打印结果是5,m=6
        System.out.println(++m);//m先自增后打印,打印结果是7

==和 equals 的区别

对于基本数据类型来说,==比较的是值。对于引用数据类型来说,==比较的是内存的地址。

Java只有值传递,所以,对于==来说,不管是比较基本数据类型还是引用数据类型,其本质都是比较值,只是引用类型变量存的值是对象的地址。

注意:string类型重写了equals方法,比较的是值
Objectequals()方法:

public boolean equals(Object obj) {
     return (this == obj);
}
        String a = "aaa";
        String b = "aaa";
        String c = new String("aaa");
        System.out.println(a == b);	//true
        System.out.println(a == c);	//false
        System.out.println(a.equals(b));	//true
        System.out.println(a.equals(c));	//true

解析:
String a = "aaa",内存会去查找永久代(常量池) ,如果没有的话,在永久代中中开辟一块儿内存空间,把地址付给栈指针,如果已经有了"aaa"的内存,直接把地址赋给栈指针。只在常量池中有一份内存空间,地址全部相同

只要是new String(),则,栈中的地址都是指向最新的new出来的堆中的地址

hashCode()与 equals()

  1. 如果两个对象相等,则 hashcode 一定也是相同的。两个对象相等,对两个对象分别调用 equals 方法都返回 true。但是,两个对象有相同的 hashcode 值,它们也不一定是相等的 。因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖。

hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

  1. HashSet 在对比的时候,同样的 hashcode 有多个对象,它会使用 equals() 来判断是否真的相同。也就是说 hashcode 只是用来缩小查找成本。

基本数据类型

8 种基本数据类型,分别为:

  1. 6 种数字类型 :byte、short、int、long、float、double
  2. 1 种字符类型:char
  3. 1 种布尔型:boolean

int是基本数据类型,默认值为0
Integer是类,属于引用数据类型,默认值为null

Java 基本类型的包装类的大部分都实现了常量池技术。
Byte,Short,Integer,Long这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character创建了数值在 [0,127] 范围的缓存数据,Boolean直接返回True Or False。两种浮点数类型的包装类Float,Double并没有实现常量池技术。

Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);

System.out.println(i1 == i2);// true
System.out.println(i1 == i2 + i3);//true
System.out.println(i1 == i4);// false
System.out.println(i4 == i5);// false
System.out.println(i4 == i5 + i6);// true
System.out.println(40 == i5 + i6);// true

i5 和 i6 会进行自动拆箱操作,进行数值相加,即 i4 == 40 。 Integer 对象无法与数值进行直接比较,所以 i4 自动拆箱转为 int 值 40,最终这条语句转为 40 == 40 进行数值比较。

String, StringBuffer, StringBuilder

String 被声明为 final,因此它不可被继承,不可变,线程安全。
StringBuilderStringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串char[]value,但是没有用final关键字修饰,所以这两种对象都是可变的。

intern()是个本地方法方法可以减少字符串在内存中的占用。如果常量池(默认有"java"字符串)中存在当前字符串,就会直接返回首次出现的引用. 如果常量池中没有此字符串,会将此字符串放入常量池中后,再返回

        String s1 = "a";
        String s2 = "b";
        String s3 = "ab";
        String s4 = s1 + s2;//new StringBuilder().append("a").append("b").toString()    new String("ab")
        String s5 = "a" + "b";
        String intern = s4.intern();//将这个字符串对象尝试放入串池,如果有则不放入,如果没有就放入并返回串池中的对象
        System.out.println(s3 == s4);//false
        System.out.println(s3 == s5);//true
        System.out.println(s3 == intern);//true

1. 可变性

  • String 不可变
  • StringBuffer 和 StringBuilder 可变

2. 线程安全

  • String 不可变,因此是线程安全的
  • StringBuilder 不是线程安全的
  • StringBuffer 是线程安全的,内部使用 synchronized 进行同步

使用的总结:

  1. 操作少量的数据: 适用 String
  2. 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

关键字

instance 关键字

instance是java的二元运算符,用来判断他左边的对象是否为右面类(接口,抽象类,父类)的实例

final 关键字

最终的、不可修改的,用来修饰类、方法和变量,具有以下特点:

  1. final 修饰的类不能被继承,final 类中的所有成员方法都会被隐式的指定为 final 方法;
  2. final 修饰的方法不能被重写;
  3. final 修饰的变量是常量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能让其指向另一个对象。

static 关键字

  1. 修饰成员变量和成员方法,不能修饰接口,接口只能用public和abstract修饰
  2. 静态代码块: 静态代码块定义在类中方法外, 静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。 该类不管创建多少对象,静态代码块只执行一次.
  3. 静态内部类(static 修饰类的话只能修饰内部类): 静态内部类与非静态内部类之间存在一个最大的区别: 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:a. 它的创建是不需要依赖外围类的创建。b. 它不能使用任何外围类的非 static 成员变量和方法。

this 关键字

用于引用类的当前实例

super 关键字

用于从子类访问父类的变量和方法
注意:

  • 构造器中使用super()调用父类中的其他构造方法时,该语句必须处于构造器的首行,this 调用本类中的其他构造方法时,也要放在首行
  • this、super 不能用在 static 方法中

访问修饰符

访问修饰符访问范围继承性
private本类内部不可继承
default本类+同包同包子类可以继承
protected本类+同包+子类可以继承
public公开可以继承

方法

方法的类型

  1. 无参数无返回值的方法
  2. 有参数无返回值的方法
  3. 有返回值无参数的方法
  4. 有返回值有参数的方法
  5. return 在无返回值方法的特殊使用
public void f5(int a) {
    if (a > 10) {
        return;//表示结束所在方法 (f5方法)的执行,下方的输出语句不会执行
    }
    System.out.println(a);
}

静态方法和实例方法

静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),不允许访问实例成员(即实例成员变量和实例方法)类名.方法名,而实例方法不存在这个限制。

重载和重写

重载是方法根据传入参数名字的不同,自动选择不同的方法执行
重写是子类继承父类的方法,但是与父类方法又有所区别

重载

发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同

不能有两个名字相同,参数相同,返回值或修饰符不同的方法

    void a(int a) {
        return ;
    }
//错误
    int a(int a) {
        return 1;
    }

重写

子类对父类的允许访问的方法的实现过程进行重新编写。

  1. 返回值类型、方法名、参数列表必须相同,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。
  2. 如果父类方法访问修饰符为 private/final/static 则子类就不能重写该方法,但是被 static 修饰的方法能够被再次声明
  3. 构造方法无法被重写

构造方法

一个类即使没有声明构造方法也会有默认的不带参数的构造方法。如果自己添加了类的构造方法(无论是否有参),Java 就不会再添加默认的无参数的构造方法了

特点

  1. 名字与类名相同
  2. 没有返回值,但是不能用void声明构造函数
  3. 生成对象时自动执行

构造方法不能被 override(重写),但是可以 overload(重载)

异常

  • error:属于程序无法处理的错误,没办法通过 catch 来进行捕获,大多数错误与代码编写者所执行的操作无关
  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。代码在编译过程中,如果受检查异常没有被 catch/throw 处理的话,就没办法通过编译
  • 运行时异常:运行时异常程序员导致的异常。即使不处理此类异常也可以正常通过编译,并不强制进行显示处理

异常的结构

Java异常类层次结构图.png

RuntimeException及其子类都统称为非受检性异常,例如:NullPointerExceptionNumberFormatException(字符串转换为数字)、ArrayIndexOutOfBoundsException(数组越界)、ClassCastException(类型转换错误)、ArithmeticException(算术错误)等

try-catch-finally

  • try块: 用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
  • catch块: 用于处理 try 捕获到的异常。若有一个catch语句匹配到了,则执行该catch块中的异常处理代码,就不再尝试匹配别的catch块了。
  • finally 块: 无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。

当 try 语句和 finally 语句中都有 return 语句时,在方法返回之前,finally 语句的内容将被执行,并且 finally 语句的返回值将会覆盖原始的返回值。如下:

public class Test {
    public static int f(int value) {
        try {
            return value * value;
        } finally {
            if (value == 2) {
                return 0;
            }
        }
    }
}
//如果调用 f(2),返回值将是 0,因为 finally 语句的返回值覆盖了 try 语句块的返回值

Q.E.D.