View on GitHub

Dmarco-v.github.io

Dmarco_v的技术博客,Java开发相关技术积累、LeetCode刷题笔记

一、数据类型

1.基本类型

java有八个基本数据类型,分别是(括号内是其对应的字节数,斜杠后是默认值,注意类的成员变量才有默认值):

隐式类型转换:(byte char short) -> int -> long -> float ->double (byte char short)相互之间不互相转化,参与运算的时候首先转化为int。无小数点的数默认为int,有小数点默认为double。

强制转换:从高级向低级转换。如 f=(float)1.0。

特殊:使用 += 或者 ++ 运算符可以执行隐式类型转换。如:

short s1=1;
s1+=1;//相当于执行了s1=(short)(s1+1);

2.包装类型

为了编程使用的方便,java引入了基本数据类型,但为了将这些基本类型当做对象进行操作,java为每个基本数据类型提供了相应的包装类型。从java 5开始引入了自动装箱/拆箱机制,从而使两者可以相互转换。

//example of boxing and unboxing
Integer a = 1;//自动装箱,调用Integer.valueOf()方法
int b = a;    //自动拆箱,调用a.intValue()方法
Integer a=new Integer(3);
Integer b=3;
int c=3;
Integer d=Integer.valueOf(3);
System.out.println(a==b);//输出false因为两个引用的是不同的对象
System.out.println(a==c);//输出true因为a会自动拆箱成int再进行比较
System.out.println(a==d);//输出false因为d是使用缓存池中的对象,而a是新建一个对象

new Integer(3)和Integer.valueOf(3)的区别在于前者每次都会创建一个新的对象,而后者是使用缓存池中的对象,多次调用会取得同一个对象的引用。java8中缓存池的大小默认为-128~127

valueOf() 方法的实现:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];//在就返回缓存池中的对象
    return new Integer(i);//不在就新建一个对象
}

补充:在 jdk 1.8 所有的数值类缓冲池中,Integer 的缓冲池 IntegerCache 很特殊,这个缓冲池的下界是 - 128,上界默认是 127,但是这个上界是可调的,在启动 jvm 的时候,通过 -XX:AutoBoxCacheMax=< size >来指定这个缓冲池的大小,该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界。

二、条件、循环与运算

1.switch语句的使用

使用时,注意每个case内都要以break结尾。

java7开始,switch语句支持使用String对象,但不支持long。

2.参数传递

一般的参数传递方式有两种:值传递和引用传递。java中采用的是值传递。意思是将一个参数传入一个方法的时候,实质上是将该对象的地址(引用类型)或值(基本类型)以值的方式传递到形参中。如果在方法中改变这个指针的指向,不会影响原指针所指的对象;而如果在方法中改变对象的某个成员变量,则会改变原对象的成员变量值。

3.逻辑运算符

逻辑运算符具有短路运算的特点。如 b1&&b2 ,如果左边的表达式为false,则右边的表达式不会执行。

4.比较运算符“==”和equals方法

对于引用类型:

对于基本数据类型,只有==运算符没有equals方法。

三、面向对象

1.构造方法

构造器是一个特殊的方法,用于创建实例时执行初始化。没有构造方法时,系统会自动生成一个默认的无参构造方法;如有,则系统不会自动生成。

在实例化一个对象的时候,会自动执行构造方法中的内容。

2.访问控制权限与package、import关键字

java中有四种访问权限

如果子类重写了父类的方法,则子类中该方法的访问级别不应低于父类的访问级别。

类中的字段不可以公有,使用公有的getter和setter方法来替换公有字段,从而实现对字段的读和写。体现了面向对象的封装特点。

package关键字用于定义包,一般会自动生成。

import关键字用于在使用不同包中的类时,导入所需的相关类。注意:如import java.util.*。只能访问util包中一级目录下的类,不能访问二级目录中的类。因为使用时如果出现一级目录和二级目录中有同名类,会出现所指不明的情况。

3.抽象类与接口

抽象类使用abstract关键字进行声明。如果一个类中包含抽象方法,必须声明为抽象类。抽象类不可被实例化,但继承了抽象类的子类可以实例化。

接口是抽象类的延伸。java8之后的接口支持拥有默认的方法实现。接口的字段和方法默认是public,不允许修饰为protected和private。接口的字段默认是static final的。

两者的比较:

注:抽象类中的抽象方法(其前有abstract修饰)不能用private、static、synchronized、native等修饰符修饰。

4. super与this关键字

super表示当前类的父类

this表示当前类

5. final与static关键字

final:

static:

6.初始化顺序

在存在继承的情况下,初始化顺序为:

7.重写与重载

重写与重载是面向对象多态性的体现。

重写(Override)是指子类实现了一个与父类在方法声明上完全相同的一个方法。

为满足里氏替换原则,重写有以下三个限制:

使用@Override注解可以让编译器自动检查是否满足三个限制条件。

在调用一个方法的时候,查找顺序如下:

8. 向上转型与向下转型

向上转型:父类引用指向子类对象。如Animal animal=new Dog(); 注意子类引用不能指向父类对象。

向下转型:把指向子类对象的父类引用赋给子类引用。如Dog dog=(Dog) animal; 注意向下转型需要强制转换。

instanceof关键字。用于向下转型时判断属于该对象属于哪个子类。

Animal animal=new Dog();
if(animal instanceof Dog){
    ((Dog)animal).fs();
}

四、Object

所有类都直接或间接的继承java.lang.Object类。由于所有的类都继承在Object类,因此省略了extends Object关键字。

常用方法有以下几个:

1.equals()

equals方法在Object类中与==相同,但在很多子类中都被重写(如String,Integer等)。一般是比较在内存中变量的值是否相同。Float和Double类中也对equals方法进行了重写,是判断他们的类型是否相同 & 数值是否相同。

2.hashCode()

hashCode() 返回散列值。等价(equals方法返回true)的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。

在重写 equals() 方法时应当总是重写 hashCode() 方法,保证等价的两个对象散列值也相等。

3.toString()

默认返回abc@12344f 的形式,@后面的值为当前对象的散列码的无符号十六进制表示。一般需要返回对象中包含的属性时,要重写toString方法

4.clone()

返回当前对象的复制对象。有以下几种实现方式:

五、String

String最大的特点在于不可变。String被final修饰,因此不可被继承。(Integer等包装类也不可被继承)

1.String类设计为不可变的好处

2.String、StringBuffer、StringBuilder的比较

3.字符串常量池

字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。

可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。

在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。

使用new String(“abc”)方法会创建两个字符串对象,在String Pool中如果没有该字符串,则会创建一个,同时还会再堆中创建一个字符串对象。而使用str=”abc”的方式,如果String Pool中已有该字符串,不会再创建新的对象,只是将str的引用指向字符串常量池中的”abc”字符串。

六、异常

1.异常基础

异常是发生在程序执行过程中阻碍程序正常执行的错误事件。

Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: Error 和 Exception。Error表示JVM无法处理的错误,Exception 分为两种:

2.异常关键字

注:finally代码块先于return语句执行,当finally代码块中有return语句,会覆盖try/catch代码块中的return语句。

3. Throwable继承关系


4. 常用方法

Exception和它的所有子类没有提供任何特殊方法供使用,它们的所有方法都是来自其基类Throwable。

七、泛型

1.泛型概念

泛型即参数化类型。将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

常用于集合中,不使用泛型会导致集合在添加元素的时候,如果添加的元素类型不一致,运行时会报类型转换异常。而如果在初始化时,将泛型声明出来,在添加与指定类型不一致的元素时,编译器就会报错。如:

List<String> arrayList = new ArrayList<String>();
arrayList.add(100);//编译不通过

2.泛型的使用方式

泛型有三种使用方式:泛型类、泛型接口和泛型方法。定义时,一般使用T、E、K、V等形式的参数常用于表示泛型。

3.通配符

例:如果将List 传递给一个接受List的方法,编译不会通过,因为类型不匹配。为了解决以上问题,需要引入通配符。

非限定通配符:

public void showKeyValue1(Generic<?> obj){
    System.out.println(obj.getKey());
}

限定通配符:

注:Array不支持泛型。因此一般建议用List来替代Array,因为List可以提供编译期的类型安全保证。

八、反射

1.反射的概念

反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。

类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。也可以使用 Class.forName("com.mysql.jdbc.Driver") 这种方式来控制类的加载,该方法会返回一个 Class 对象。反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

2.反射的作用

3.反射的优缺点

反射的优点:

反射的缺点:

深入解析Java反射

九、其他

1.JRE与JDK

2.变量命名规则

由字母、数字、$和下划线组成,不能以数字开头,不能使用关键字。

3.序列化与transient关键字

序列化的含义:

transient关键字的作用就是让被修饰的成员变量不被序列化,可以节省一定的存储空间。一般有两种情况可以用transient关键字修饰:

注意:

参考资料