hashCode()方法和equals()方法的作用其实是一样的,在Java里都是用来对比两个对象是否相等一致。
那么equals()既然已经能实现对比的功能了,为什么还要hashCode()呢?因为重写的equals()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高。
那么hashCode()既然效率这么高为什么还要equals()呢? 因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,
所以我们可以得出:
1.equals()相等的两个对象他们的hashCode()肯定相等,也就是用equals()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
所有对于需要大量并且快速的对比的话如果都用equals()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equals(),如果equals()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
HashSet内部使用Map保存数据,即将HashSet的数据作为Map的key值保存,这也是HashSet中元素不能重复的原因。而Map中保存key值前,会去判断当前Map中是否含有该key对象,内部是先通过key的hashCode,确定有相同的hashCode之后,再通过equals方法判断是否相同。
public class TestObj{
public static void main(String[] args){
Object o=new Object(){
public boolean equals(Object obj){
return true;
}
};
System.out.println(o.equals(“Fred”));
}
}
本题涉及匿名内部类、多态和覆盖三个知识点。
语句Object o=new Object(){ public boolean equals(Object obj){ return true; } };
创建了一个匿名内部类,并将所创建的匿名对象赋给 Object (多态:子类对象赋给超类引用)。同时,该匿名内部类重写了 Object 类的 equals 方法。
在执行语句o.equals(“Fred”)时,根据多态及覆盖原则,会调用匿名内部类重写后的 equals 方法。
根据以下代码段,下列说法中正确的是( )。
public class Parent {
private void m1(){}
void m2(){}
protected void m3(){}
public static void m4(){}
}
A 子类中一定能够继承和覆盖Parent类的m1方法
B 子类中一定能够继承和覆盖Parent类的m2方法
C 子类中一定能够继承和覆盖Parent类的m3方法
D 子类中一定能够继承和覆盖Parent类的m4方法
解读:
通过继承,子类可以拥有所有父类对其可见的方法和域
A.私有方法只能在本类中可见,故不能继承,A错误
B.缺省访问修饰符只在本包中可见,在外包中不可见,B错误
C.保护修饰符凡是继承自该类的子类都能访问,当然可被继承覆盖;C正确
D.static修饰的成员属于类成员,父类字段或方法只能被子类同名字段或方法遮蔽,不能被继承覆盖,D错误。
子父类存在同名静态函数访问的是父类。
package xufeng;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Collection<?>[] collections = { new HashSet<String>(), new ArrayList<String>(),
new HashMap<String, String>().values() };
Super subToSuper = new Sub();
for (Collection<?> collection : collections) {
System.out.println(subToSuper.getType(collection));
}
}
abstract static class Super {
public static String getType(Collection<?> collection) {
return "Super:collection";
}
public static String getType(List<?> list) {
return "Super:list";
}
public String getType(ArrayList<?> list) {
return "Super:arrayList";
}
public static String getType(Set<?> set) {
return "Super:set";
}
public String getType(HashSet<?> set) {
return "Super:hashSet";
}
}
static class Sub extends Super {
public static String getType(Collection<?> collection) {
return "Sub";
}
}
}
运行结果:
A:
Sub:collection
Sub:collection
Sub:collection
B:
Sub:hashSet
Sub:arrayList
Sub:collection
C:
Super:collection
Super:collection
Super:collection
D:
Super:hashSet
Super:arrayList
Super:collection
答案解读:
C
运行结果:
重载,[静态分配]: 参数匹配看实参定义(等号)的左边。 所以本题都是调用collection。
重写,[动态分派]: 调用谁的方法,看对象定义的右边。 本题是静态方法,并不是重写,而是属于子类独有的静态方法,又因为是向上转型,所以这时候只能访问父类与子类共有的属性,所以此时调用的是父类的方法。
静态属性和静态方法只是可以继承没有表现出多态性。
因为静态方法和静态属性没有采用动态绑定。
具体表现就是,
将子类实例向上转型则会调用到基类中的静态方法和属性,
不转型就调用子类自身的静态方法和属性。
编译器不推荐通过实例去调用静态方法和属性,因为这种调用方式容易造成混淆。
以下哪种JAVA的变量表达式使得变量a和变量b具有相同的内存引用地址( )
String a = "hello"; String b = "hello";
Integer a; Integer b = a;
int a = 1; Integer b = new Integer(1);
int a = 1; Integer b = 1;
内存引用地址,是指栈中存放的地址,来指向堆中的某个位置。
int 是基本类型,数据直接存放在栈中,不存在内存引用地址的说法
==
A对 指向常量池里的"hello"。
B对 题中没说声明的a是局部变量。
C错 int a =1;并不指向堆中,它只有值,没有引用地址,Integer b =new Integer(1);指向堆中地址为1的位置。
D错 原因同C
(1)int与Integer、new Integer()进行==比较时,结果永远为true
(2)Integer与new Integer()进行==比较时,结果永远为false
(3)Integer与Integer进行==比较时,看范围;在大于等于-128小于等于127的范围内为true,在此范围外为false。
对于构造方法,下列叙述正确的是( )。
A 构造方法的优先级一般比代码块低。
B 构造方法的返回类型只能是void型。
C 构造方法的主要作用是完成对类的对象的初始化工作。
D 一般在创建新对象时,系统会自动调用构造方法。
解析:
A:静态成员变量或静态代码块>main方法>非静态成员变量或非静态代码块>构造方法
B:think in java中提到构造器本身并没有任何返回值。
C: 构造方法的主要作用是完成对类的对象的初始化工作。
D: 一般在创建(new)新对象时,系统会自动调用构造方法。
构造方法没有返回值类型,也不写void
代码块:
分类:静态代码块和实例代码块
静态代码块:static修饰的代码块,在类加载时执行,且只执行一次。因为类就加载一次了。
实例代码块:没有static修饰的代码块,创建对象时执行,每创建一次对象加载一次。
实例代码块在执行构造方法之前执行。所以优先级高于构造方法。
java程序初始化顺序:
父类静态变量,父类静态代码块(只执行一次),
子类静态变量,子类静态代码块(只执行一次),
父类非静态变量,父类非静态代码块,父类构造函数,
子类非静态变量,子类非静态代码块,子类构造函数
归纳一下:
父静子静,父实例子实例。
先变量再代码块,最后再构造
public class NameList
{
private List names = new ArrayList();
public synchronized void add(String name)
{
names.add(name);
}
public synchronized void printAll() {
for (int i = 0; i < names.size(); i++)
{
System.out.print(names.get(i) + ””);
}
}
public static void main(String[]args)
{
final NameList sl = new NameList();
for (int i = 0; i < 2; i++)
{
new Thread()
{
public void run()
{
sl.add(“A”);
sl.add(“B”);
sl.add(“C”);
sl.printAll();
}
} .start();
}
}
}
链接:https://www.nowcoder.com/questionTerminal/25deb8d21e7d442e86c90302d6e03133
来源:牛客网
Which two statements are true if this class is compiled and run?
-
An exception may be thrown at runtime.
-
The code may run with no output, without exiting.
-
The code may run with no output, exiting normally(正常地).
-
The code may rum with output “A B A B C C “, then exit.
-
The code may rum with output “A B C A B C A B C “, then exit.
-
The code may ruin with output “A A A B C A B C C “, then exit.
-
The code may ruin with output “A B C A A B C A B C “, then exit.
解析:EG
分2段打印。
第2个部分线程一定是最后6个。
起始部分和余下的第1部分一定是重复的。