基础知识点
java关键字
abstract 表明类或者成员方法具有抽象属性
assert 断言,用来进行程序调试
boolean 基本数据类型之一,声明布尔类型的关键字
break 提前跳出一个块
byte 基本数据类型之一,字节类型
case 用在switch语句之中,表示其中的一个分支
catch 用在异常处理中,用来捕捉异常
char 基本数据类型之一,字符类型
class 声明一个类
const 保留关键字,没有具体含义
continue 回到一个块的开始处
default 默认,例如,用在switch语句中,表明一个默认的分支。Java8 中也作用于声明接口函数的默认实现
do 用在do-while循环结构中
double 基本数据类型之一,双精度浮点数类型
else 用在条件语句中,表明当条件不成立时的分支
enum 枚举
extends 表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口
final 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量
finally 用于处理异常情况,用来声明一个基本肯定会被执行到的语句块
float 基本数据类型之一,单精度浮点数类型
for 一种循环结构的引导词
goto 保留关键字,没有具体含义
if 条件语句的引导词
implements 表明一个类实现了给定的接口
import 表明要访问指定的类或包
instanceof 用来测试一个对象是否是指定类型的实例对象
int 基本数据类型之一,整数类型
interface 接口
long 基本数据类型之一,长整数类型
native 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的
new 用来创建新实例对象
package 包
private 一种访问控制方式:私用模式
protected 一种访问控制方式:保护模式
public 一种访问控制方式:共用模式
return 从成员方法中返回数据
short 基本数据类型之一,短整数类型
static 表明具有静态属性
strictfp 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范
super 表明当前对象的父类型的引用或者父类型的构造方法
switch 分支语句结构的引导词
synchronized 表明一段代码需要同步执行
this 指向当前实例对象的引用
throw 抛出一个异常
throws 声明在当前定义的成员方法中所有需要抛出的异常
transient 声明不用序列化的成员域
try 尝试一个可能抛出异常的程序块
void 声明当前成员方法没有返回值
volatile 表明两个或者多个变量必须同步地发生变化
while 用在循环结构中
final
解读:final关键字是java的一个修饰符,可以用来声明类,方法,属性。
被final修饰的类,方法,属性,具有以下特点:
1)final修饰类,该类不可被继承
2)final修饰方法,该方法不可被重写,可以被继承和重载
3)final修饰属性,该属性为常量,不可改变
如何理解equals和hashcode?
现假设有对象A和B,如果A.equals(B)==true,那么对象A和对象B的对象内容相等,hashcode也相同。(hashcode相同对象不一定相同);
equals必须满足3个特性:对称性,自反性,一致性;
在重写equals方法时一定要重写hashcode方法;
equals和运算符双等号的区别
1)equals:父类的equals方法是用来比较方法两个对象的地址是否相等,String类的equals方法是用来比较两个字符串的内容是否相同。equals方法不能用于基本数据类型的变量,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址,如果重写了equals,就看equals的具体实现规则
2)"==":如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等
先来一段代码测试一下:
package com.test;
import org.omg.CORBA.PRIVATE_MEMBER;
public class Test {
public static void main(String[] args) {
String s1 = "123";
String s2 = "123";
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
String s3 = new String("456");
String s4 = new String("456");
System.out.println(s3.equals(s4));
System.out.println(s3 == s4);
}
}
输出结果:
"C:\Program Files\Java\jdk1.8.0_212\bin\java.exe" "-javaagent:D:\JetBrains\IntelliJ IDEA 2019.3.2\lib\idea_rt.jar=54178:D:\JetBrains\IntelliJ IDEA 2019.3.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_212\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\rt.jar;F:\workspace\springtest\target\classes;D:\resp\org\springframework\spring-core\4.3.18.RELEASE\spring-core-4.3.18.RELEASE.jar;D:\resp\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\resp\org\springframework\spring-context\4.3.18.RELEASE\spring-context-4.3.18.RELEASE.jar;D:\resp\org\springframework\spring-aop\4.3.18.RELEASE\spring-aop-4.3.18.RELEASE.jar;D:\resp\org\springframework\spring-beans\4.3.18.RELEASE\spring-beans-4.3.18.RELEASE.jar;D:\resp\org\springframework\spring-expression\4.3.18.RELEASE\spring-expression-4.3.18.RELEASE.jar;D:\resp\org\springframework\spring-jdbc\4.3.18.RELEASE\spring-jdbc-4.3.18.RELEASE.jar;D:\resp\org\springframework\spring-tx\4.3.18.RELEASE\spring-tx-4.3.18.RELEASE.jar" com.test.Test
true
true
true
false
Process finished with exit code 0
再来看一个例子,关于equals方法重写和不重写比较的差异:
package com.test.main;
public enum EnumA {
NAME(1,"1");
private int code;
private String name;
EnumA(int code, String name) {
this.code = code;
this.name = name;
}
}
package com.test.main;
public class Test {
public static void main(String[] args) {
TestB testB = new TestB();
boolean result = EnumA.NAME.equals(testB.getEnum());
System.out.println(EnumA.NAME.hashCode());//枚举EnumA的hashcode
System.out.println(testB.getEnum().hashCode());//TestB的hascode
System.out.println(result);
//因为Enum默认重写了equals和hashcode方法,内部比较的也是地址,但是枚举类是静态类,对象是放在一个共享空间,所以==比较的结果地址是一样的,返回true
// 打印结果:
//1977594184
//1977594184
//true
TestB testb2 = new TestB();
TestB testb3 = new TestB();
boolean result2 = testb2.equals(testb3);
System.out.println(testb2.hashCode());//testb2的hashcode
System.out.println(testb3.hashCode());//testb3的hashcode
System.out.println(result2);
//因为TestB没有重写equals和hashcode方法,所以equals比较的是对象的引用地址,因为用的是Object父类的equals方法,查看源码可以知道比较的是引用地址
// 打印结果:
//821045869
//1735488308
//false
}
}
&和&&的区别
&和&&运算结果是一致的,他们的区别在于:
if(a==1 & b ==2){};//这里两边都会判断一遍
if(a1 && b2){};//这里只有当a1成立才会接着判断b2,如果a1不成立,那么后面的b2不会去判断。
重载和重写的区别
两者都为java多态的体现;
重载:方法名相当,参数的顺序,类型,个数不同,返回类型可以不同;
PS:为什么不能根据返回类型不同来区分重载?
answer:因为有返回值的方法可以选择不接收,当调用两个方法名一样的方法,其他相同,一个有返回值,一个没有返回值的时候,java编译器认为方法重复,不知道调用哪个;
重写:方法名和参数完全一致,但构造方法,final和static修饰的方法不能被重写;访问权限不能比父类低
java是值传递和引用传递
这个问题深究起来也是非常复杂的,这里简单的理解一下,java只有值传递;
当一个对象实例被当做参数传递到其他方法当中时,参数的值就是该对象的内存地址,该内存地址指向的堆内容是可以被改变的,也就是说对象当做参数传递,可以改变对象的内容。
理解抽象类和接口
抽象类:abstract class
接口:interface
简单的理解:abstract 用来定义一个抽象类,而interface用来定义接口;
abstract不能实例化;
abstract类中可以有普通成员方法,也可以有abstract 修饰的抽象方法;
abstract定义的abstract方法在子类必须有实现;
abstract不能和static,native,synchronized同时使用,因为抽象类要有实现,可static不能被实现,native和synchronized都和方法实现相关;
interface接口类中所有的的方法都没有方法体,都是抽象的,都必须在实现类中进行实现;
interface接口类中的所有成员变量都默认为public static final;
一个类可以实现N个接口,但是只能继承一个父类;
public,protected,default,private 访问区别
hashmap和hashtable的区别
hashmap允许key和value都为null,为非线程安全;
hashtable不允许,线程安全;
看一下源码:
Hashtable.class:
public synchronized V put(K var1, V var2) {
if (var2 == null) {
throw new NullPointerException();
} else {
Hashtable.Entry[] var3 = this.table;
int var4 = var1.hashCode();
int var5 = (var4 & 2147483647) % var3.length;
for(Hashtable.Entry var6 = var3[var5]; var6 != null; var6 = var6.next) {
if (var6.hash == var4 && var6.key.equals(var1)) {
Object var7 = var6.value;
var6.value = var2;
return var7;
}
}
this.addEntry(var4, var1, var2, var5);
return null;
}
}
hashtable用了syncchronized修饰,表示线程安全;
再来看一下hashmap的源码:
public V put(K var1, V var2) {
return this.putVal(hash(var1), var1, var2, false, true);
}
final V putVal(int var1, K var2, V var3, boolean var4, boolean var5) {
HashMap.Node[] var6;
int var8;
if ((var6 = this.table) == null || (var8 = var6.length) == 0) {
var8 = (var6 = this.resize()).length;
}
Object var7;
int var9;
if ((var7 = var6[var9 = var8 - 1 & var1]) == null) {
var6[var9] = this.newNode(var1, var2, var3, (HashMap.Node)null);
} else {
Object var10;
Object var11;
if (((HashMap.Node)var7).hash == var1 && ((var11 = ((HashMap.Node)var7).key) == var2 || var2 != null && var2.equals(var11))) {
var10 = var7;
} else if (var7 instanceof HashMap.TreeNode) {
var10 = ((HashMap.TreeNode)var7).putTreeVal(this, var6, var1, var2, var3);
} else {
int var12 = 0;
while(true) {
if ((var10 = ((HashMap.Node)var7).next) == null) {
((HashMap.Node)var7).next = this.newNode(var1, var2, var3, (HashMap.Node)null);
if (var12 >= 7) {
this.treeifyBin(var6, var1);
}
break;
}
if (((HashMap.Node)var10).hash == var1 && ((var11 = ((HashMap.Node)var10).key) == var2 || var2 != null && var2.equals(var11))) {
break;
}
var7 = var10;
++var12;
}
}
hashmap没有相关修饰,为非线程安全,高并发下,put可能会发生哈希冲突;ConcurrentHashMap为线程安全的map集合类,都属于java对象;
先写到这里吧,太晚了,睡了睡了