1)重写equals方法的时候为什么需要重写hashcode?
Java的object中equals的实现:
public boolean equals(Object obj) {
return (this == obj);
}
可以看到是用来比较两个对象的内存地址是否相等。
hashCode方法是本地方法,用于计算出对象的一个散列值,用于判断在集合中对象是否重复的关键。
在源码注解中大致讲述看:当我们将equals方法重写后有必要将hashCode方法也重写,这样做才能保证不违背hashCode方法中“相同对象必须有相同哈希值”的约定。
作者定义hashCode:将对象的地址值映射为integer类型的哈希值。
- 一个对象多次调用它的hashCode方法,应当返回相同的integer(哈希值)。
- 两个对象如果通过equals方法判定为相等,那么就应当返回相同integer。
- 两个地址值不相等的对象调用hashCode方法不要求返回不相等的integer,但是要求拥有两个不相等integer的对象必须是不同对象。
总的来说:
- 相同的对象必然导致相同的哈希值。
- 不同的哈希值必然是由不同对象导致的。
在String源码中比较两个对象除了在两个对象的内存地址相等的时候返回true,还会在比较其对应的字符都相等的时候也返回true。所以现在可以得到“因为必须保证重写后的equals方法认定相同的两个对象拥有相同的哈希值”。同时我们顺便得出了一个结论:“hashCode方法的重写原则就是保证equals方法认定为相同的两个对象拥有相同的哈希值”。
同时我们从HashMap中分析(key对象必须重写equals和hashCode)
- 无论是 put 还是 get 的时候,都需要得到key的哈希值,去定位key的数组下标;
- 在 get 的时候,需要调用equals方法比较是否有相等的key存储过。
User user1=new User("name");
User user2=new User("name");
HashMap<User, String> hashmap=new HashMap<User,String>();
hashmap.put(user1, "value1");
String str=hashmap.get(user2);
System.out.println("输出结果:"+str);//null
上面的例子都未重写equals,所以在查找user2的时候使用的object的equals,比较的是地址,而user1和user2的地址肯定不同,所以找不到。(即使重写了equals而没有重写hashCode也不一定能找的,应为他们的地址不同所以找到的数组下标也不一定相同
2)八种基本类型
整型:byte(8bit)short(16bit)int(32bit)long(64bit)
浮点型:float(32bit)double(64bit)
字符型:char(2字节,16bit)
布尔型:boolean(为true和false,默认值为false)
3)键盘输入(脑抽插播)
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String name = sc.nextLine();
int age = sc.nextInt();
float f = sc.nextFloat();
}
}
4)String底层的数组使用的是final修饰,即如 str1+str2是new了一个String
可以使用stringBuild和stringBuffer的
《Think in Java》中,描述
HashTable和HashMap区别一样,就是因为HashTable支持线程同步、保证线程安全而导致的性能下降。
HashTable是线程安全的,很多方法都是synchronized方法。
HashMap不是线程安全的,但在单线程程序中的性能比HashTable要高。
而现在StringBuffer和StringBuilder类的区别也在于此,StringBuilder类不是线程安全的,但其在单线程中的性能比StringBuffer高。
5)抽象类和接口的区别
抽象类可以有抽象方法和非抽象方法而接口值能有抽象方法(默认修饰)(但在JDK1.8中接口可以有default和static方法)。
抽象类只能单继承(extends),而接口可以多实现(implements)。
抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。
接口只能由static final变量,而抽象类可以有普通变量(因为防止多实现不统一的改变变量,而抽象类是单继承的所以没问题)。
6)普通类和抽象类的区别
抽象类不能被实例化。
抽象类中抽象方法不需要实现。
(含有抽象方法的类必须声明为抽象类abstract class 类名,接口inteface类名)。
7)访问修饰符
public《-protected《-default《-private
1234 123 12 1
1其他包 2当前包 3子类 4当前类
8)自动装箱和自动拆箱
//自动装箱
Integer total = 99;//调用valueOf()
//自动拆箱
int totalprim = total;//调用intValue,对应别的是xxxValue()
9)&与&&
&&之所以称为短路运算,是因为左边为false时右边直接跳过了返回false,
if(x==33 & ++y>0) y会增长,if(x==33 && ++y>0)不会增长,(&&使用时需要注意顺序,比如比较为null和空字符串时)
&还可以用作位运算符,只有对应的两个二进位都为1时,结果位才为1。
10)JDK、JRE、JVM
JDK是java开发工具包( JDK包含了JRE,同时还包括java源码的编译器javac、监控工具jconsole、分析工具jvisualvm等)
JRE是java运行时环境(用户只需要有jre即可运行程序),java虚拟机(JVM),java基础类库
JVM Java虚拟机,加载.class并运行.class
11)final和static
static表示静态或全局,被修饰的属性和方法属于类,可以用类名.静态属性 / 方法名 访问
static属性:静态变量或者叫全局变量,类变量,被修饰的属性和方法属于类,可以用类名.【静态属性 |方法名】 访问
static 修饰的代码块表示静态代码块,当 Java 虚拟机(JVM)加载类时,就会执行该代码块,只会被执行一次(单例模式可以使用
static方法必须被实现不能是抽象的,而且不能被重写
static不能以任何方式调用this和super和非静态方法,因为在类加载时,对象未初始化前已经把类的static加载到了jvm的方法区(此时如果没被final则基本数据类型会被赋值为默认值,0,false。。。,特别的,如static final int init = 100,则会被赋值为100),所以不知道非静态方法
final修饰属性:基本数据类型-值不能改变,对象-引用地址不能变但是对象内容课可以改变
final修饰方法:方法不能被重写
final修饰类:类不能被继承,final 类中的方法默认是 final 的
结!
不写了困了,睡觉前刷一题简单题:
题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
import java.util.LinkedList;
import java.util.Queue;
class Solution {
public int movingCount(int threshold, int rows, int cols)
{ if(threshold < 0)
return 0;
int[] dp = new int[(1+rows)*(1+cols)];
dp[0] = 1;
int[][] kunsile = {{1,0},{-1,0},{0,1},{0,-1}};
Queue<Integer> queue = new LinkedList<Integer>();
queue.add(0);
int sum = 1;
int w;
while(queue.peek() != null){
w = queue.poll();
int l = w/cols;
int r = w%cols;
for(int i = 0; i < kunsile.length; i++){
int ll = l + kunsile[i][0];
int rr = r + kunsile[i][1];
if(ll<0 || rows <= ll || rr < 0 || cols <= rr){
continue;
}
if(dfs(ll,rr,threshold) && dp[ll*cols+rr]==0){
dp[ll*cols+rr] = 1;
sum++;
queue.add(ll*cols+rr);
}
}
}
return sum;
}
public boolean dfs(int ll, int rr, int threshold){
int sum = 0;
while(ll != 0){
sum += ll%10;
ll/=10;
}
while(rr != 0){
sum += rr%10;
rr/=10;
}
return sum > threshold ? false :true;
}
};