一、类的修饰符
不能使用
private
和protected
修饰一个类(内部类除外)
二、构造器重载
在一个构造器中调用另外一个构造器,可使用关键字
this
; 且调用应该放在构造器的第一个行,且只能调用一个this
三、多态
只有普通方法的调用能发生多态; 属性字段没有多态一说。
四、 组合接口时的名字冲突
如果返回值或者签名(参数列表) 不同,可能会造成冲突,所以尽量避免。
五、boolean类型的私有属性的get方法
boolean类型的私有属性的get方法是以 `is`开头
5.1 案例
public class TestBooleanField {
private boolean canRead = false;
public boolean isCanRead() {
return canRead;
}
public void setCanRead(boolean canRead) {
this.canRead = canRead;
}
public static void main(String[] args) {
}
}
5.2 尽量不要以 is 开头给字段命名
public class TestBooleanField {
private boolean isFlag = true;
public boolean isFlag() {
return isFlag;
}
public void setFlag(boolean flag) {
isFlag = flag;
}
}
如果以 is
开头给字段命令,在快速生成getter
方法时,或出现上诉这样的问题。这样会操作一些很隐秘的错误。
七、打印保留小数位数
System.out.printf("%.2f",3454.437893723);
System.out.printf("hello%s","world");
八、字符串
String
是不可变类
public class Test {
public static void main(String[] args) {
String str[] ={"abc","def"};
replace(str[0],str[1]);
System.out.println(str[0]+str[1]); //abcdef
}
public static void replace(String s1,String s2){
String s = s1;
s2 = s1;
s2 = s;
}
}
九、转换问题
short a =128;
byte b = (byte)a;
---结果
-128
需要明白
向下转换
的本质。(截取操作)
十、关键字static
static
不允许修饰局部变量
十一、final 修饰的成员变量
必须要给定初始值、在定义或者构造器中赋值。
十二、自动类型提升
打印结果是 9.0
public static void main(String[] args) {
int a = 5;
System.out.println("value is "+((a<5) ?10.9 : 9));
//value is 9.0
}
十三、异常处理
/**
* 打印结果
* try
* exception
* finally
* @param args
*/
public static void main(String[] args) {
try{
System.out.println("try");
throw new Exception();
}catch(Exception e){
System.out.println("exception");
}finally{
System.out.println("finally");
}
}
十四、初始化问题
static{
x = 1;
}
static int x,y;
public static void main(String[] args) {
x--;
System.out.println(x+"::"+y+"---1");
method();
System.out.println(x+"::"+y+"---2");
System.out.println( x + y + ++x);
System.out.println(x+"::"+y+"---3");
}
public static void method(){
x++;
y = x++ + x;
}
/**
* 0::0---1
* 2::3---2
*8
*3::3---3
*/
案例2
public class Test1 {
static{
int x = 5;
}
static int x,y;
public static void main(String[] args) {
x--;
myMethod();
System.out.println(x + y++ +x);
}
private static void myMethod() {
y = x++ + ++x;
}
}
//-------------结果是2-------------
package chd.edu;
public class Test1 {
static{
x = 5;
}
static int x,y;
public static void main(String[] args) {
x--;
myMethod();
System.out.println(x + y++ +x);
}
private static void myMethod() {
y = x++ + ++x;
}
}
//-----结果是22-------------
解释原因:
static{
int x = 5;//局部变量
}
十五、 i++
下面
j
的打印结果是多少
public static void main(String[] args) {
int j=0;
for(int i=0;i<100;i++){
j = j++;
}
System.out.println(j);
}
打印结果
0
j=j++
等同于下面:
temp = j;
j = j+1;
j = temp;
十六 try - finally
public class Test {
public static void main(String[] args) {
System.out.println(new Test().test());
}
private int test() {
try{
return fun1();
}finally{
return fun2();
}
}
public int fun1(){
System.out.println("fun1");
return 1;
}
public int fun2(){
System.out.println("fun2");
return 2;
}
}
打印结果
fun1
fun2
2
十七、 String中的一个方法
substring
public String substring(int beginIndex,
int endIndex)
返回一个新字符串,它是此字符串的一个子字符串。该子字符串从指定的 beginIndex
处开始,直到索引 endIndex - 1
处的字符。因此,该子字符串的长度为 endIndex-beginIndex。
十八、线程问题
public class MyThread extends Thread{
public void run(){
System.out.println("Run="+this.isAlive());
System.out.println(this.getId()+"---"+this.getName());
System.out.println(Thread.currentThread().getId()+"----"+Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread MyThread = new MyThread();
MyThread.setName("MyThread");
Thread thread = new Thread(MyThread,"thread");
thread.start();
}
}
Run=false
10---MyThread
11----thread
//注意区别:this 与Thread.currentThread()
public class MyThread extends Thread{
public void run(){
System.out.println("Run="+this.isAlive());
System.out.println(this.getId()+"---"+this.getName());
System.out.println(Thread.currentThread().getId()+"----"+Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread MyThread = new MyThread();
MyThread.setName("MyThread");
MyThread.start();
}
}
Run=true
10---MyThread
10----MyThread
十九、序列化和反序列化 、串行化和并行化
19.1 序列化和反序列化
应用场景: 当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为对象。
- 把对象转换为字节序列的过程称为对象的序列化。
- 把字节序列恢复为对象的过程称为对象的反序列化。
序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable
只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream
)来构造一个ObjectOutputStream
(对象流)对象,接着,使用ObjectOutputStream
对象的writeObject(Object obj)
方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
对象的序列化主要有两种用途:
1)把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2)在网络上传送对象的字节序列。
19.2 串行化和并行化
串行化也叫做序列化
,就是把存在于内存的对象数据转化成可以保存成硬盘文件的形式去存储;
并行化也叫反序列化
,就是把序列化后的硬盘文件加载到内存,重新变成对象数据.
二十、 String 相等
稍微有点经验的程序员都会用equals
比较而不是用 ==
,但用equals
就真的安全了吗,看下面的代码
user.getName().equals("xiaoming");
有经验的老司机很快就能看到问题,如果user.getName()
为null,就会抛出空指针异常,因此下面的写法更为稳妥
"xiaoming".equals(user.getName());
当然这种写法并不是万能的,如果比对的两边都是未知变量,如下
user.getName().equals(user1.getName());//user.getName() 和 user1.getName()都有可能为null
因此更为稳妥的方法可以采用jdk Objects类中的equals方法,左右两边都可以避免空指针异常
Objects.equals(user.getName(), user1.getName());
需要注意的是Objects类在jdk1.7才支持,如果是jdk1.6,可以采用guava中的Objects类代替
二十一、Arrays.asList()
其底层表示的是数组,因此不能调整尺寸,如果你试图用add()
或delete()
方法在这种列表中添加或删除元素就有可能引发去改变数据尺寸的尝试。因此你将在运行时获得unsupported Operation
错误。
二十二、String.CASE_INSENSITIVE_ORDER
二十三、 java forEach实现原理
jdk api文档中是这样描述Iterable
接口的:实现这个接口允许对象成为 foreach
语句的目标
foreach
语法最终被编译器转为了对Iterator
的调用;(java提供的语法糖)
二十四、 final成员变量初始化
必须要对final修饰的属性进行初始化,不然会报错;要么在定义时,要么在构造器中。
二十五、类型提示
如果对byte 或short 值进行移位运算,得到的可能不是正确的结果,它们会被转成int类型,再进行右移操作,然后被截断,赋值给原来的类型
只要类型比int小(即char、byte 或者short)在进行算数运算或者按位运算时,会自动转成int; 这样一来最终生成结果就是int 类型
编译通不过,自动类型提升了。
二十六、初始化顺序
更多细节查看类加载器相关。
- 父类–静态变量
- 父类–静态初始化块
- 子类–静态变量
- 子类–静态初始化块
- 父类–变量
- 父类–初始化块
- 父类–构造器
- 子类–变量
- 子类–初始化块
- 子类–构造器
二十七、Random使用
Random类中实现的随机算法是伪随机,也就是有规则的随机。在进行随机时,随机算法的起源数字称为种子数(seed
),在种子数的基础上进行一定的变换,从而产生需要的随机数字。
相同种子数的Random对象,相同次数生成的随机数字是完全相同的。也就是说,两个种子数相同的Random对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。这点在生成多个随机数字时需要特别注意
二十八、JAVA正则表达式中如何匹配反斜杠 \
JAVA中匹配反斜杠的正则表达式的书写方式:
String regex="\\\\";
第一和第三个反斜杠是用作java字符串的转义,实际上只代表两个反斜杠
二十九、String类的intern()方法
参看这篇博客:Java技术——你真的了解String类的intern()方法吗
三十、增强for
增强型for循环和普通循环比较
- 对于非集合类(没有实现
Iterable
接口)的数组遍历,增强型for循环和普通循环遍历原理相同,效率相同 - 对于集合类(实现了
Iterable
接口),增强型for循环的遍历其本质就是迭代器iterator
的遍历,和普通循环遍历相比,各自有自己适用的场景,比如说普通for循环比较适合List类(数组类)遍历通过下标查找数据的,而增强型for循环则比较适合链表结构的集合的遍历。
三十一、获取对象的方法
1 用new语句创建对象,这是最常见的创建对象的方法。
2 还有就是这种
String emp0 = String.valueOf(23);
String emp1 = "123";
3 运用反射手段,调用java.lang.Class
或者java.lang.reflect.Constructor
类的newInstance()
实例方法。
CreateInstance instance =(CreateInstance)Class.forname("com.create.instance.CreateInstance").newInstance();
Employee emp2 = Employee.class.newInstance();
4 运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
bjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp4 = (Employee) in.readObject();
5 clone()克隆方法。
Employee emp5 = (Employee) emp3.clone();
三十二、clone()方法
32.1 浅复制与深复制概念
浅复制(浅克隆)
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不 复制它所引用的对象。
深复制(深克隆)
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
32.2 Java的clone()方法
⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
32.3 Java中对象的克隆
①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
②在派生类中覆盖基类的clone()方法,并声明为public。
③在派生类的clone()方法中,调用super.clone()。
④在派生类中实现Cloneable接口
三十三、String.format()
public static Result failure(int totalSize, int sucessSize, int failSize) {
String msg = String.format("总共%d条,成功%d条,失败%d条", totalSize, sucessSize, failSize);
return new Result(FAILURE, msg);