Java 基础
cmd 命令行编译乱码问题
public class Hello {
public static void main(String[] args) {
System.out.println("你好");
}
}
// 编译时指定编码方式,避免乱码
javac -encoding utf8 Hello.java
在 .java 文件所在目录,输入 cmd,即可进入当前目录,方便快捷!
文档注释
javadoc -encoding utf8 -version -author -d mydir Hello.java
标识符
字母、数字、_、$、中文(不建议用)
数据类型
char,gbk 占 2 字节,utf-8 占 3 字节
long l2 = 30000000000l; // 超过 Integer 范围,必须要后加 l/L
float f = 2.1f; // 必须带 f/F,因为默认浮点型是 double 类型的,double 不能自动转成 float
char c = 23578; // 只能赋值 [0, 65535] 范围,对应字符集编码值,如 A -> 65,a -> 97
运算符
int i = 1;
// (先赋值再自增)① i 赋值给 i++ ② i 自增 ③ i++ 赋值给 i
i = i++;
System.out.println(i); // 10
int j = 1;
System.out.println(j == j++); // true
// j = ++(i++); // 错误,++ 只能用于变量
int m = 1;
// (先自增后赋值)① m 自增 ② m 赋值给 ++m ③ ++m 赋值给 m
m = ++m;
int r = 1;
/*
① r 赋值给 r++,r = 1, r++ = 1
② r 自增,r = 2, r++ = 1
③ r++ - r = 1 - 2 = -1
④ r 赋值给 r++, r = 2, r++ = 2
⑤ r 自增,r = 3, r++ = 2
⑥ (r++ - r) + r++ = -1 + 2 = 1
*/
int s = r++ - r + r++;
System.out.println(s); // 1
int f = 1;
boolean b = f > 1 & f++ > 1; // & 不短路,&& 短路
System.out.println(f); // 2
System.out.println(2 > 1 ? 100 : 9.0); // 100.0,类型提升
short s = -32768; // 在 [-32768, 32767] 范围内,正确
// s = s + 10; // 类型提升至 int,编译报错
s += 10; // 正确
输入
Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();
System.out.println(i);
// 读取上面的换行,避免之后输入不了
scanner.nextLine();
String s = scanner.nextLine();
System.out.println(s);
流程控制结构
if(s > 10) int a = 10; // Declaration not allowed here(只有一行代码,变量声明没有意义,不可能被使用)
int i = 10;
switch (i) { // switch 支持 byte,short,int,char,String(JDK 1.7 新增),枚举
case 10:
System.out.println(10);
case 11:
System.out.println(11);
case 12:
System.out.println(12);
break;
default:
System.out.println(0);
}
// 输出,遇到 break 或 } 执行结束
/*
*
* 10
* 11
* 12
*
* */
数组
// 二维数组 arr 各元素指向的各个一位数组相互独立
int[][] arr = new int[][]{
{1,2},
{11, 22, 33}
};
常见错误
System.out.println(null);
System.out.println(091); // 0 开头表示八进制数,八进制数最大数字位应小于 8
int i; System.out.println(i); // 没初始化,不允许使用
面向对象
参数传递机制内存分析
class Person {
int id;
String name;
Person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person(1, "Tom");
fun(person);
System.out.println(person);
}
public static void fun(Person person) {
person = new Person(2, "Jack");
System.out.println(person);
}
}
/*
Person{id=2, name='Jack'}
Person{id=1, name='Tom'}
*/
this/super
起点不同,终点相同,this 从自己开始,super 从父亲开始,没有就继续找父亲!
使用方法和属性的时候其前面都会默认带有 this.,此 this 具体指的是哪个类呢?方法看实际对象,属性来本类!
public class Test {
static class Father {
public String name = "Father";
public void f() {
// 属性看类(父类的 name)
System.out.println("Father f() " + this.name);
// 方法看对象(如果是 Son 调用 f(),那么此处调用的就是 Son 的 common())
this.common();
}
public void common() {
System.out.println("Father common()");
}
}
static class Son extends Father {
public String name = "Son";
public void common() {
System.out.println("Son common()");
}
}
public static void main(String[] args) {
Son son = new Son();
son.f();
}
}
/*
Father f() Father
Son common()
*/
static class Person {
public String name = "Father";
public Person(String name) {
this.name = name;
// 此时 Person 对象尚未初始化完成,其子类 Student 对象尚未初始化
// this.f() 调用的是子类的 f(),子类的 name = null
f();
}
public void f() {
System.out.println(name);
}
}
static class Student extends Person {
private String name = "Son";
public Student(String name) {
super(name);
}
public void f() {
System.out.println(name);
}
}
public static void main(String[] args) {
Student student = new Student("Tom"); // null
}
static class Person {
public String name = "Father";
public Person(String name) {
this.name = name;
System.out.println("Person 构造器");
}
}
static class Student extends Person {
private String name = "Son";
private int no;
public Student(String name, int no) {
// 必须在首行,调用父类的构造器,不能与 this 同时存在,不写此行代码,默认也会有 super(),
// 也就是说默认是调用父类的无参构造器。得保证父类有对应的构造器
super(name);
System.out.println("Student 构造器");
}
}
public static void main(String[] args) {
Student student = new Student("Tom", 20210001);
}
/*
Person 构造器
Student 构造器
*/
权限修饰符
本类 | 本包 | 其他包(子类) | 其他包(非子类) | |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
默认 | √ | √ | × | × |
private | √ | × | × | × |
多态
父类引用指向子类,必须调用重写方法
// 向下转型
class A {}
class B extends A {}
class C extends A {}
public class Test {
public static void main(String[] args) {
A a = new B();
// 注意判断,判断运行时对象类型是否属于类
if (a instanceof B) {
B b = (B) a; // 向下转型
}
if (a instanceof C) {
C c = (C) a; // 向下转型风险,a 只能转成 B,若不判断,会抛异常 java.lang.ClassCastException
}
}
}
// 多态数组
class A {}
class B extends A {}
class C extends A {}
public class Test {
public static void main(String[] args) {
A[] arr = new A[3];
arr[0] = new A();
arr[1] = new B();
arr[2] = new C();
}
}
Object
// 垃圾回收
class A {
@Override
protected void finalize() throws Throwable {
// 回收垃圾的时候会调用这个方法
System.out.println("A() finalize");
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
// 导致刚才创建的那个 A 无处引用,成为垃圾
a = new A();
// 通知垃圾回收机制进行垃圾回收
System.gc();
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("finish");
}
}
接口
interface MyInterface {
// 静态方法(JDK 1.8 新增),只能这么调用:myInterface.staticMethod()
public static void staticMethod() {
System.out.println("staticMethod()");
}
// 通过实现类对象调用,可以被重写
public default void defaultMethod() {
System.out.println("defaultMethod()");
}
}
- 如果实现类的父类和实现的接口中有相同的方法,会调用父类的方法
- 如果实现类的实现的多个接口中有相同的方法,实现类必须重写该方法
- 调用实现接口的方法(接口.super.接口默认方法)
Comparable
所有用到 A 的地方,都会按照相同的排序规则,影响面大!后面的 Comparator 只影响自己一处。
class A implements Comparable<A> {
int id;
public A (int id) {
this.id = id;
}
@Override
public int compareTo(A o) {
if( this == o) {
return 0;
}
return this.id - o.id; // return Integer.compare(this.id, o.id);
}
@Override
public String toString() {
return "A{" +
"id=" + id +
'}';
}
}
public class Test {
public static void main(String[] args) {
A[] as = new A[3];
as[0] = new A(1);
as[1] = new A(3);
as[2] = new A(2);
// 调用 compareTo 进行比较、排序
Arrays.sort(as);
for(A a: as) {
System.out.println(a);
}
}
}
Comparator
class A {
int id;
public A (int id) {
this.id = id;
}
@Override
public String toString() {
return "A{" +
"id=" + id +
'}';
}
}
class MyComparator implements Comparator<A> {
@Override
public int compare(A o1, A o2) {
// if(o1.id < o2.id) {
// return -1;
// } else if(o1.id > o2.id) {
// return 1;
// } else {
// return 0;
// }
return o1.id - o2.id;
}
}
public class Test {
public static void main(String[] args) {
A[] as = new A[3];
as[0] = new A(1);
as[1] = new A(3);
as[2] = new A(2);
// Arrays.sort(as, new Comparator<A>() {
// @Override
// public int compare(A o1, A o2) {
// return o1.id - o2.id;
// }
// });
// Arrays.sort(as, (o1, o2) -> o1.id - o2.id);
// Arrays.sort(as, Comparator.comparingInt(o -> o.id));
Arrays.sort(as, new MyComparator());
for(A a: as) {
System.out.println(a);
}
}
}
内部类
class Outer {
String name = "Outer";
class Inner {
String name = "Inner";
public void innerMethod() {
System.out.println(name); // Inner
System.out.println(Outer.this.name); // Outer
}
}
}
局部的东西不能是静态的,因为静态的是属于类的!
String
常量 + 常量,或调用 intern 方法会存入常量池中,其他都存入堆