《Java核心技术》第一讲
5.2、equals、hashcode、toString
package com.macro.mall; import java.util.Objects; public class Employer { private String name; private int age; @Override public boolean equals(Object otherObject) { //检测Object是否为空 if (otherObject == null) { return false; } //检测this和Object是否指向同一个对象 if (this == otherObject) { return true; } //比较this和Object是否属于同一个类 if (getClass() != otherObject.getClass()) { return false; } //将Object转换成相应的类类型变量 Employer employer = (Employer) otherObject; /** 由于会存在属性值为空的情况,因此如果属性值都为空,Objects.equals则返回true 如果是数组类型比较的话,那么就使用Arrays.equals进行比较 */ return name == employer.name && age == employer.age && Objects.equals(name, employer.name) && Objects.equals(age, employer.age); } @Override public int hashCode() { return Objects.hash(name, age); } /** * 通过使用getClass().getName()方法,防止类名硬编码 * 此外,如果子类继承该类的话,那么可以就可以通过super.toString进行调用。 * 如 * public String toString() { * return super.toString() * +"[bonus=" + bonus * + "]"; * } */ @Override public String toString() { return getClass().getName() + "name=" + nameB + ", age=" + age + "}"; } }
instanceOf可以用来判断是不是指定的一个类或者类的子类或者实现类
如果A类和B类,B类继承了A类,有4种情况:
创建B对象,也就是B b=new B()
1、b instanceOf B true
2、b instanceOf A true,因为B对象继承了A类
创建A对象,也就是A a = new A()
3、a instance A true
4、a instance B false,B类继承了A类,也就是说B类有的东西A类不一定存在。
同理,实现类也就如此,
5.4 自动装箱与拆箱(编译器执行,而非虚拟机)
基本数据类型:int(4个字节)、short(2个字节)、long(8个字节)、char、byte(1个字节)、float、double、boolean
引用数据类型包括:类(java提供的类或者我们自己定义的类)、接口、数组、枚举、标注
Integer、Short、Long、Char、Byte、Float、Double、Boolean都是java提供的类,因此也是引用类型。
自动装箱:把基本属性类型转换成对应的对象。
自动拆箱:把对象转换成基本属性类型。
如Integer a =10 这个是装箱。首先看=后面的值为10,属于int类型,但是前面是Integer,因此把int类型转成Integer对象。拆箱的话即相反。
5.6 实例化对象
反射机制获取类对象的三种方式:
1、类.getClass 2、Class.forName(String类型的类名) 3、T.class
获取到这些class后,然后调用newInstance方法即可进行实例化。
和new 对象不同的是,new对象的时候Class类被创建了并且已经被实例化了。
而通过类加载机制也就是反射获取的话需要进行实例化也就是调用newInstace方法。
newInstace和new的不同;
newInstace的话只能调用无参构造,而new没有限制,其次newInstace是个方法,而new是一个关键字。
最后通过newInstace的话在工厂模式中可以进行解耦,比如下面代码。
String className = "接口的继承类"; AService o = (AService) Class.forName(className).newInstance();
如上,className可以用个方法封装获得,那么和每次都要new 对象相比的话代码耦合性就会降低。
但是这个也有个弊端,就是newInstance的效率会比较低。
5.7异常
异常包括未检查异常(unchecked运行时异常)和已检查异常(checked)。
未检查异常:空指针异常、数据越界异常等,可以抛出异常。
已检查异常:不能抛出,只能try..catch
6.3 lambda表达式
在一个包含lambda表达式的方法中,方法的参数及引用变量都是不可变的,也就是final。
比如一个方法:public void test(int a,int b) lambda表达式中不能存在类似 a++这种操作或者说有个for循环:for(int i=0;i<count;i++) 然后lambda表达式中引入i,这种会发生变化的变量是不允许存在的,否则会报错。
6.4 内部类
www.cnblogs.com/dearcabbage/p/10609838.html
www.cnblogs.com/wuhenzhidu/p/anonymous.html
8.1 泛型
泛型使用类型参数的好处,比如有如下代码
ArrayList list =new ArrayList(); list.add(new File(".....")); File file=(File)list.get(0);
比如上面代码,没有加类型参数的话,ArrayList的话里面可以添加任意类的对象,但是在获取的时候就需要强制转换成不同的类型,此外,在添加并且获取的时候由于没有类型参数编译器不会进行检查,安全性大大降低,而引用了类型参数后就可以解决可读性和安全性。
类型变量的限定
public static <T extends Comparable> T get(String name) { }
注意:这里的话T extends Comparable的话可能会有点奇怪,因为Comparable是个接口,应该是Implements,
官方说明:<T extends BoundingType>,表示T是BoundingType的子类型,T和BoundingType可以是类,也可以是接口,选择extends的原因是更接近子类的概念。
8.5 泛型擦除
Java的泛型是伪泛型,这是因为在编译期间,泛型类型都会被擦除掉,比如下面的代码。
public class Test { public static void main(String[] args) { ArrayList<String> list1 = new ArrayList<String>(); list1.add("abc"); ArrayList<Integer> list2 = new ArrayList<Integer>(); list2.add(123); System.out.println(list1.getClass() == list2.getClass()); } }
定义了2个List,泛型分别是String和Integer类型,但是我们分别获取他们的class,然后进行比较,最后结果会返回true
类型擦除后会变成原始类型,原始类型的通用表达:如果是无限定的类型变量就用Object替换,如果是有限定的类型变量就用这个限定的变量进行替换。
如
class Pair<T> { private T value; public T getValue() { return value; } public void setValue(T value) { this.value = value; } }
T的话就是无限定的类型变量,那么T就会被替换成Object
class Pair { private Object value; public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } }
同理,如果最初的泛型为Pair(T extends Comparable),那么T会被替换Comparable。