1 需要注意的点
1.1 运算赋值操作
- 复合赋值运算中(如:+=、-=等),隐含了类型强制转换。如:
byte b = 126; // 按常理2是int型,byte + int 结果应该是int,但这里会强转为byte b += 2; // 结果会溢出 System.out.println(b); // -128
- 三目运算不能单独存在,运算结果必须要有“接收方”
OperationDemo.java:10: 错误: 不是语句 a > b ? a : b; ^ 1 个错误
- 整数类型中byte、short、int、long四种的前三种在运算时都会先转换为int类型;
byte a = 10; byte b = 20; // 事实上是byte = int + int,所以编译时会报错 byte ret = a + b;
OperationDemo.java:5: 错误: 不兼容的类型: 从int转换到byte可能会有损失 byte ret = a + b; ^ 1 个错误
- 如果表达式的右边为常量,编译时会先将表达的进行计算,用结果替换原来的表达式,如:
// 上述示例中ret = a + b,表达式右边是int型,左边是byte,有转换失真的风险所以编译会报错; // 但如果右边是常量则不会,byte ret = 10 + 20类似直接写byte ret = 30; byte ret = 10 + 20;
1.2 函数与方法
- 方法重载中如果返回值类型不一样,不构成方法重载。(想想看,返回值是可以强制类型转换的,那么编译器到底该给哪个方法呢?所以此处有歧异)
public static int sum(int a, int b) { return a + b; } // 编译报错,方法重名了,仅返回值类型不同不构成方法重载 public static float sum(int a, int b) { return (float) (a + b); }
1.3 数组
- 数组初始化的几种方式,主要有静态初始化(指定值)与动态初始化(指定长度);
- 所谓的静态与动态区别是即时指定长度还是直接赋值;
- Java中指定值有两种方式,一种是类型前缀,一种不加(所谓的标准格式与省略格式);
- 在其他高级语言中如C++,静态初始化不能拆开写(即省略格式),但Java标准格式可以;
- 动态初始化数组时,内存中全部写
0
,即int为0
、float为0.0
、对象为null
、char为\u0000
;// 动态初始化,在创建数组时指定数组长度 int[] array1 = new int[10]; System.out.println(array1); int[] array2 = new int[10]; System.out.println(array2); // 静态初始化,创建数组时直接以数据长度为准 int[] array3 = new int[] {1, 2, 3, 4}; System.out.println(array3); int[] array4 = {1, 2, 3, 4}; System.out.println(array4); // 初始化可以先定义变量再赋值,但有一种情况例外 int[] array5; array5 = new int[10]; int[] array6; array6 = new int[] {1, 2, 3, 4}; int[] array7; array7 = {1, 2, 3, 4}; // 注意:这种情况是非法的,编译报错
2 相关总结
2.1 类与对象
局部变量与成员变量的区别
- 定义的位置不一样
- 局部变量:在方法的内部
- 成员变量:在方法的外部,直接写在类中
- 作用范围不一样
- 局部变量:只有在当前方法中才可以使用,出了方法则不可用
- 成员变量:整个类中都可以使用
- 默认值不一样
- 局部变量:没有默认值,使用前必须赋初始值
- 成员变量:编译器会自动赋默认值
- 内存位置不一样
- 局部变量:位于栈内存
- 成员变量:位于堆内存
- 生命周期不一样
- 局部变量:随着方法进栈而生,随着方法出栈而亡
- 成员变量:随着对象的创建而诞生,随着对象被垃圾回收而消失
2.2 字符串
创建字符串常用的4种方法(3种构造函数方法+1种字面量直接创建)
- 构造函数
String()
String str = new String(); //
- 构造函数
String(char[] charArray)
char[] charArray = {'A', 'B', 'C'}; String str = new String(charArray); // ABC
- 构造函数
String(byte[] byteArray)
byte[] byteArray = {97, 98, 99}; String str = new String(byteArray); // abc
- 字面量
String str = "string"; // string
字符串在内存的表现形式
- 不管通过什么方式创建的字符串,所有的字符串都是对象;
- 通过字面量的形式创建的字符串,指向的堆空间的一个字符串常量池(共用字符串对象);
- 通过对象通过字符串的构造方法创建的字符串,先转换成char数组,再在堆中生成对象指定这个数组;
public class StringDemo {
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abc";
char[] charArray = {'a', 'b', 'c'};
String str3 = new String(charArray);
/**
* 引用类型通过“==”比较的是地址
* 通过字面量直接创建的字符串,指向的是堆中的“字符串常量池”
* 通过char数组创建的字符串,在堆中指向char数组转换后的另一片地址空间str->堆1->堆2
*/
System.out.println(str1 == str2); // true
System.out.println(str2 == str3); // false
System.out.println(str3 == str1); // false
}
}
2.3 接口的基本使用
抽象方法的定义 public abstract 返回类型 方法名(参数列表);
实现类中必须实现接口中的所有抽象方法,除非是抽象类。
public abstract void abstractMethod1();
public abstract void abstractMethod2();
public abstract void abstractMethod3();
public abstract void abstractMethod4();
默认方法的定义 public default 返回值类型 方法名(参数列表){}
接口的实现类中可以选择性地实现该方法,SDK8.0及以上支持。
/**
* 默认方法(解决升级的问题)
* 该方法实现类中可以被重写,也可以省略,因为这里有实现体
*/
public default void defaultMethod() {
System.out.println("接口类的默认方法...");
}
静态方法 public static 返回类型 方法名(参数列表){}
该特性从SDK8.0及以后才支持
public static void show() {
System.out.println("MyInterfaceAbstract static method..");
}
私有方法的定义 privat 返回值类型 方法名(参数列表){}
,这种方法的定义在SDK9.0及以后的版本才支持,解决默认方法中功能的抽象,分为普通方法与静态方法,静态方法只能通过接口名调用。
// 普通私有方法
private void commonMethod() {
System.out.println("common method...");
}
// 静态私有方法
private static void staticMethod() {
// coding...
}
静态常量 public static final 数据类型 常量名 = 值
需要注意的是:常量命名使用大写;public static final 可以省略但效果一样。
public static final int NAME_LENGTH = 10;
需要注意的是:
- 接口中不能有静态代码块
static {}
- 接口实现类可以同时实现多个接口
implements intA, intB
- 如果多个接口中抽象方法重名,只需要实现一次即可,如果是默认方法则必须重写
- 如果没有实现接口的所有方法,只能是抽象类
- 如果继承的方法与接口的方法冲突,则继承的方法优先级较高
- 类只能单继承,但接口可以多继承。
2.4 包装类的使用
int
、Integer
、String
之间的相互转换,其它基本数据类型以此类推
// int --> Integer
// Integer i = new Integer(1);
Integer a = Integer.valueOf(1);
Integer a1 = 1;
// Integer --> int
int b = a.intValue();
int b1 = a;
// String --> Integer
Integer c = Integer.valueOf("1");
// String --> int
int d = Integer.parseInt("1");
// Integer --> String
String e = c.toString();
// int --> String
String f = String.valueOf(1);