Java 基础
1. static 方法:
- 静态方法中只能引用外部的静态属性
- 静态方法中也只能引用静态的内部类(即被 static 修饰的类)
2. this关键字: this 关键字是不能在 static 方法或者 static 代码块中使用的
3. 异常处理:
- 带返回值的方法:
public boolean save(String filename){
/*
* 保存文件
*/
try{
File file = new File(path + filename);
...
// 未产生异常
return true;
} catch (FileNotFoundException e){
// 产生异常
return false;
}
}
- 不带返回值的方法:
public void save(String filename) throws FileNotFoundException{
File file = new File(path + filename);
...
}
4. 内部类访问外部类的属性需要加 final 关键字:
- 错误代码:
public class Test {
private String name;
private class Test1{
public void sayHello(){
System.out.println("Hello, My name is " + name); // 会报错
}
}
}
- 正确代码:
public class Test {
private final String name; // 加上了 final 关键字修饰
private class Test1{
public void sayHello(){
System.out.println("Hello, My name is " + name);
}
}
}
5. new 关键字:
for(int i = 0; i < 1000; i ++){
Message msg = new Message();
msg.what = UPDATE_PROGRESS; // 更新进度
// ....
}
for(int i = 0; i < 1000; i ++){
Message msg = Message.obtain(); // 使用 api,以避免创建新对象
// ...
}
6. 抽象类:
- 抽象类中不仅可以有被 abstract 修饰的抽象方法,还可以有非抽象方法。抽象方法不能实现,而非抽象方法可以实现
- 抽象类和接口的通俗规则:[摘自《设计模式之禅》]
- 接口:负责定义 public 属性和方法以及声明与其他对象的依赖关系
- 抽象类:负责公共构造部分的实现,实现业务逻辑以及适当时对父类进行细化
- 若基类是抽象类,且该类的某方法已经得以实现,则子类尽量不要重写该方法[摘自《设计模式之禅》]
7.final关键字:
- 若 final 修饰的是基础数据类型的变量,如 final int i = 5;则该变量就是常量,其值不可变
- 若 final 修饰的是集合类型变量,如此处的 List 集合,则该变量的引用不可变,但是可以进行增删改的操作
- 若 final 修饰的是类,则该类不可以被继承
- 若 final 修饰的是方法,则该方法可以被继承,但是不可以被修改(private 方法被隐式的指定为 final 方法)
8.接口的种类:(2种)
- 实例接口:Object Interface,即使用Class声明的类,然后用 new 实例化,这个类就是一个接口。如 Person p = new Person(); 产生了一个实例 p,那么该 Person 类就是 p 的接口[记住 Java 中的类也是一种接口]
- 类接口:Class Interface,即被 interface 关键字修饰的接口
9. 尽量避免在循环体中创建对象:
先给出错误编码:for(int i = 0; i < 10000; i ++){ Object obj = new Object(); // 坏处:这样会在内存中产生大量的对象引用,浪费大量的内存空间,增大 GC 的负荷 System.out.println("wrong, obj=" + obj); }
正确的编码方式:
即:正确的方法时,先在循环体外声明好需要使用的变量并置为空,然后再在循环体内初始化Object obj = null; for(int i = 0; i < 10000; i ++){ obj = new Object(); // 好处:无论循环多少次,依旧仅在内存中保存一份对该对象的引用 System.out.println("right. Obj = " + obj); }
10. 使用完一个对象后,将其置为 null,释放其强引用,这样可以帮助 JVM 及时的回收垃圾对象:
public class Test { public static void main(String[] args){ Object obj = new Object(); // 使用 obj // .... // 使用完毕 obj = null; // 不要忽视这句代码的作用,它可以帮助你更好的管理内存,优化系统运行速度 } }
11. Java引用和C、C++ 中指针的区别:
Java的引用几乎等同于C、C++ 中的指针,但是并不完全等同于。比如对于一个 int 类型的数组 arr,在C 中,指向该数组的指针 p 可以进行 ++ 操作,移动到下一个内存单元;但是Java中却不可以,绝对是通不过的。因此,可以说:Java 的引用是不可计数的指针
12. Java 数组的注意事项:
Person[] persons = new Person[4];
for(int i = 0; i < 4; i ++){
persons[i] = new Person();
}
对于上面的这一小段代码,是否存在疑问?为什么会要有 2 次 new 操作?
我们可以回想一下在 C 语言中,进行内存时的场景,就可以理解了。为什么会进行 2 次 new 操作呢?
因为,第一次的 new 操作,是给数组 persons 分配了一个连续的内存空间,但是 persons[1] 等,它们却是没有值的,即其值为 null。第二次的 new 操作,才是对每一个小的内存单元进行实例化,这些内存单元才会存在实际数据。[关于数组,一定要注意这一点]
13. 在产品级研发中,方法的过时或废弃应该使用 @Deprecated 注解,而不是直接删除
不要有删除投产中代码的念头,如果方法或类确实不能在使用了,增加该注解
我们应该保持历史原貌,同时也有助于版本向下兼容,特别是在产品级研发中
/**
* 旧方法
*/
@Deprecated
public static Person getPerson(){
return new Person();
}
/**
* 新的方法
*/
public static Person getPerson(String key){
// ...
}
14. 子线程中是无法使用 return 语句来返回数据的
15. Java Swing编程错误之关闭当前窗体时关闭了系统
再Java Swing编程中,可以使用 setDefaultCloseOperation() 方法来实现关闭当前窗体但不退出系统。但是在我使用该方法时却不依旧退出了系统。这是为什么呢?经过不断调试,才发现,我对 setDefaultCloseOperation() 的调用是写在自定义的 JFrame 中的。若是将该方法的调用写在创建自定义窗体的类中,才有效果。小结:不能写成 this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 即不能再自定义 Frame 组件中调用该方法,只能在创建该窗体的类中进行设置,否则无效 new MyFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE)
16. 异常java.lang.UnsupportedOperationException
List list = Arrays.asList(a[]);
List arrayList = new ArrayList(list);
17. 关于继承中的private修饰
Java中的有与权限相关的有三个修饰关键字(public、private、protected)和包访问权限。其中private是仅对本类对象公开;protected是对本类及其子类对象公开,并提供包访问权限。在类间继承时,得注意 private 所修饰的属性:private 修饰的属性是可以继承的,但子类不可以直接访问父类中被 private 修饰的属性。class A {
private String name;
public String getName () {
return name;
}
}
class B extends A {
public void test () {
System.out.println(name); // 这是错误的,编译器报错,没有 name 属性
}
}
class A {
private String name;
public String getName () {
return name;
}
}
class B extends A {
public void test () {
System.out.println(super.getName()); // 这样才是正确的
}
18. Java中的基本数据类型
8种基本数据类型:int、short、long、float、double、char、byte、boolean--->5个与数字相关的
各自所占的字节数:
- char:2 byte
- boolean:1 bit
- short:2 byte
- int、float:4 byte
- long、double:8 byte
19.Java 整数默认为 int,小数默认为 double
// float f = 3.4; // 编译报错
float f = 3.04f; // 若要使用单精度需在后面加上字母f或F
f = 3;
short s = 1;
// s = s + 1; // 编译报错,因为 s + 1 是的结果是 int 的,需要转型为 short
s = (short) (s + 1);
s += 1; // 相当于s1 = (short)(s1 + 1); 其中进行了隐含的强制类型转换
20. Java中“字符数据池”的内存管理机制
该机制会在对一个字符串赋值之前,检查池中有没有相同的数据,若有,则直接引用,否则,会 new 一个 String 对象,在堆上新开辟一个空间,存储该对象,并在栈上存储指向该对象的引用。
String s1 = "Hello,World";
String s2 = new String("Hello,World"); // 这句话创建了2个字符串对象,一个静态区的"Hello,World",一个new在堆上的对象
String s3 = "Hello" + ",World";
System.out.println(s1 == s2); // false
System.out.println(s1 == s3); // true
System.out.println(s1 == s2.intern()); // true,注意 intern() 方法
21. Java 不能根据返回值类型来区分重载
public void f () {
System.out.println("1");
}
public int f () {
return 1;
}
上面那段代码是会出现编译报错的,报错内容为:Duplicate method f() in type Test。为什么会这样呢?因为有时候我们并不关心方法的返回值,想要的只是方法调用的其他效果。如我们在使用时,直接使用 f(); 而不用一个变量来接受其参数值,那么此时 Java 不知道该去调用哪一个 f() 方法,因此根据方法的返回值来区分重载方法是行不通的。
22. Java 类的初始化顺序
初始化顺序如下:类的静态成员(从父类到子类)---> 父类构造器--->子类非静态成员---->子类构造器
Note:前往 bascker/javaworld 获取更多 Java 知识