默认学过C或C++,对变量、表达式、选择、循环都会。
运行特征
- 解释型语言(JavaScript、Python等)
源文件-(平台专属解释器)->解释器中执行 - 编译型语言(C++、Go等)
源文件-(平台编译器)->平台可执行文件 - Java
源文件-(通用编译器)->.class二进制文件-(平台JVM)->JVM中执行
Java名词解释
- JVM(Java Virtual Machine)虚拟机
- JRE(Java Runtime Environment)运行环境(包含JVM和解释器),有这个就能运行Java程序
- JDK(Java Development Kit)包含JRE和相关工具的Java开发环境
常用Dos命令
dir查目录,不是ls
cd进目录
d:进D盘
mkdir创建文件夹
rd删除文件夹
cls清屏
exit退出
Java的相关文件(Windows平台)
.java文件:Java源代码文件,包含了程序员编写的Java代码。.class文件:Java字节码文件,是由Java编译器编译生成的中间代码文件,可以由Java虚拟机(JVM)执行。.jar文件:JavaArchive文件,是一种归档文件格式,用于将多个Java类文件、资源文件和元数据打包成一个文件。通常用于分发和部署Java应用程序、库或组件。java.exe:Java程序的执行器,用于执行已编译成的Java字节码文件(.class文件)。javac.exe:Java编译器,用于编译Java源代码文件(.java文件)成为Java字节码文件(.class文件)。jar.exe:Java归档工具,用于创建和管理Java归档文件(.jar文件),可以将多个.class文件打包成一个可执行的JAR文件。javadoc.exe:Java文档生成工具,用于根据源代码中的注释生成API文档,将Java代码注释转换为HTML格式的文档。jdb.exe:Java调试器,用于在调试Java程序时启动Java调试器,允许暂停程序、检查变量值、设置断点等操作。javap.exe:Java反汇编器,用于反编译Java字节码文件(.class文件)成为Java源代码的形式,可以查看.class文件的内容,了解其中包含的类、方法、字段等信息。
一个Java程序开发通常如下:编写.java源文件,使用javac.exe编译成.class文件,使用java.exe执行.class文件(不能带.class后缀,直接java 类名)。
基本数据类型
- 整型(Integer Types):
- byte:8位,有符号,范围为 -128 到 127。
- short:16位,有符号,范围为 -32,768 到 32,767。
- int:32位,有符号,范围为 -2^31 到 2^31 - 1。
- long:64位,有符号,范围为 -2^63 到 2^63 - 1。
123L
- 浮点型(Floating-Point Types):
- float:32位,单精度浮点数,范围为大约 1.4e-45 到 3.4e+38,精确度为约 7 位小数。
12.2f - double:64位,双精度浮点数,范围为大约 4.9e-324 到 1.8e+308,精确度为约 15 位小数。
- float:32位,单精度浮点数,范围为大约 1.4e-45 到 3.4e+38,精确度为约 7 位小数。
- 字符型(Character Type):
- char:16位,Unicode字符,范围为 ‘\u0000’(即 0)到 ‘\uffff’(即 65,535)。
- 布尔型(Boolean Type):
- boolean:表示 true 或 false 值。
易错:

引用数据类型
- 类(Class):类是用户定义的数据类型,用于创建对象。类包含属性(字段)和方法,可以通过实例化(创建对象)来访问它们。
- 接口(Interface):接口是一种抽象数据类型,用于定义类应该实现的方法。类可以实现一个或多个接口,以达到实现多态性和代码复用的目的。
- 数组(Array):数组是一组相同类型的数据元素的集合。数组在内存中是连续存储的,可以通过索引访问其中的元素。
- 枚举(Enum):枚举是一种特殊的类,用于定义一组命名的常量。枚举常量通常用于表示有限的一组可能值,如星期几、月份等。
- 字符串(String):字符串是Java中的特殊对象,用于表示文本数据。字符串是不可变的,可以进行各种操作,如连接、截取、替换等。
- 包装类(Wrapper Classes):包装类是一种将基本数据类型封装为对象的类。Java提供了一组包装类,如Integer、Double、Boolean等,用于在需要对象的上下文中使用基本数据类型。
- 自定义引用数据类型:除了以上提到的内置引用数据类型外,开发人员还可以创建自定义的引用数据类型,通过定义类和接口来实现自己的数据结构和算法。
控制台输入
import java.util.Scanner;class UseScanner {public static void main(String[] args) {Scanner input = new Scanner(System.in);System.out.println("Input your name: ");String name = input.next(); // 取字符串System.out.println("OK~ next... input your age: ");int age = input.nextInt(); // 取整数System.out.println("Hello " + name + ". And your age is " + age + ". Choose A or B please.");char a = input.next().charAt(0); // 取字符串第0个字System.out.println("You choose " + a);input.close();}
}
Java特别注意
- switch语句中允许接受
byte、short、int、char、String作为变量,但不支持long
数组
class UseArray {public static void main(String[] args) {int[] arr; // 声明数组arr = new int[5]; // 分配空间int[] arr2 = { 1, 2, 3, 4, 5 }; // 声明,并(包含分配空间)赋值printArray(arr);System.out.println();printArray(arr2);}static void printArray(int[] arr) {for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);}}
}
class UseArray {public static void main(String[] args) {int[] arr = { 1, 2, 3 };// 拷贝扩容arr = Arrays.copyOf(arr, 10);printArray(arr);// 也能截取arr = Arrays.copyOf(arr, 2);printArray(arr);}static void printArray(int[] arr) {System.out.println(Arrays.toString(arr));}
}
import java.util.Arrays;class UseArray {public static void main(String[] args) {int[] arr = { 1, 2, 3 };printArray(arr);arr = extendArray(arr);printArray(arr);addArray(arr);printArray(arr);}static void printArray(int[] arr) {System.out.println(Arrays.toString(arr));}// 传入的是arr所指的地址static void addArray(int[] arr) {arr[0] = 10086;}static void extendArray(int[] arr) {arr = Arrays.copyOf(arr, 10);return arr;}}

可变长参数
只能放最后一个参数位置,作为数组形式使用。
class UseArray {public static void main(String[] args) {System.out.println(sumup("Hello", 1, 2, 3, 4, 5, 6, 7));}public static int sumup(String str, int... nums) {int sum = 0;System.out.println("Input String: " + str);for (int i = 0; i < nums.length; i++) {sum += nums[i];}return sum;}}
二维数组
class UseArray {public static void main(String[] args) {int[][] arrs1 = new int[3][5];arrs1[0][0] = 0;printArrays(arrs1);int[][] arrs2 = new int[3][];arrs2[0] = new int[5];arrs2[1] = new int[3];arrs2[2] = new int[1];printArrays(arrs2);int[][] arrs3 = { { 1, 2, 3 }, { 2, 3 }, { 3 } };printArrays(arrs3);return;}public static void printArrays(int[][] arrs) {for (int i = 0; i < arrs.length; i++) {for (int j = 0; j < arrs[i].length; j++)System.out.print(arrs[i][j] + " ");System.out.println();}System.err.println("--------------");return;}}
面向对象基础
public class Person {String name;int age;public void speak(String words) {System.out.println(name + "say: " + words);}public void jump() {System.out.println(name + "jumps to " + age);}
}
public class Test {public static void main(String[] args) {Person person = new Person();person.name = "小明";person.age = 18;person.speak("哈哈哈");person.jump();}
}
- 类由成员变量和方法组成
- 类中定义的变量是成员变量,实例化后存在堆空间中,创建后就有默认值,不会因为没有初始化成员变量而报错。
- 局部变量的优先级高于成员变量,在类方法中的同名局部变量会先于成员变量。如果在方法中需要使用成员变量,需要加上
this.来访问。
方法重载
一个类中定义多个相同名称的方法,但是参数列表不同(类型、顺序、个数不同都算不同)。这与形参名、方法访问修饰符、返回值类型无关!
可以参考println()函数的实现,有很多方法重载的例子。、
public void println(boolean x) {if (getClass() == PrintStream.class) {writeln(String.valueOf(x));} else {synchronized (this) {print(x);newLine();}}
}
public void println(char x) {if (getClass() == PrintStream.class) {writeln(String.valueOf(x));} else {synchronized (this) {print(x);newLine();}}
}
构造方法
类中的特殊方法,与类名同名。
没有返回值类型,只在创建对象时调用,无法通过方法调用。
没有在类中显式定义构造方法,由编译器提供无参构造方法。
构造方法也可以重载!在定义带参构造后需要补充无参构造!
public class Person {String name;int age;public Person() {System.out.println("Person created!");}public Person(String name) {this.name = name;}public void speak(String words) {System.out.println(name + "say: " + words);}public void jump() {System.out.println(name + "jumps to " + age);}
}
对象的创建步骤

this关键字
指向当前实例对象。实际是对象在虚拟机中的堆地址(在new的时候就已经确定)
- 在类方法中,可以避免与局部同名变量冲突。用于调用成员变量/方法。
- 构造方法内自调用
this()
public class Person {String name;int age;public Person() {System.out.println("Person created!");}public Person(String name) {this.name = name;}public Person(String name, int age) {this(name);this.age = age;}public void speak(String words) {System.out.println(name + "say: " + words);}public void jump() {System.out.println(name + "jumps to " + age);}
}
封装
隐藏必要的对象内部实现细节,控制对象属性、方法的使用与修改权限。
使用访问修饰符private(私有,仅本类可见)。
属性的访问与修改使用getter和setter。
public class Person {String name;int age;private int score;public void setScore(int score) {if (score >= 0 && score <= 100)this.score = score;elsethis.score = 0;}public int getScore() {return this.score;}
}
继承
使用extends关键字继承父类,实例化子类时,会先调用父类的构造方法,然后调用子类的构造方法。
默认会调用无参父类构造,如果需要调用带参构造,使用super(a,b,c...)调用。
子类创建对象时并没有创建父类对象,只是在子类空间中创建了super指向的父类空间,所以只有一个子类对象实例。
public class Animal {private String name;int age;private double price;public Animal() {System.out.println("Animal Created!");}public Animal(String name) {System.out.println("Animal with name Created!");setName(name);}public Animal(String name, int age, double price) {this.name = name;this.age = age;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}}
public class Dog extends Animal {int age;public Dog() {super("MAKA");System.out.println("Dog created!");this.age = 233;super.age = 666;}public void speak() {System.out.println(getName() + " wang wang!");}}
public class Test {public static void main(String[] args) {Dog pt = new Dog();System.out.println(pt.age);pt.speak();return;}
}
// Animal with name Created!
// Dog created!
// 233
// MAKA wang wang!
属性的继承
父类的所有属性都可以被继承,但是私有属性不能被访问。
当子类和父类有同名属性时,通过super关键字区分,没标注this/super优先访问this的。

public class Sup {int a;int b;}
public class Sub extends Sup {int b;public void speak() {System.out.println("a: " + a);System.out.println("this.b: " + this.b);System.out.println("super.b: " + super.b);}
}
public class Test {public static void main(String[] args) {Sub sub = new Sub();sub.a = 1;sub.b = 2;sub.speak();return;}
}// a: 1
// this.b: 2
// super.b: 0
方法的覆盖(重写)
当父类提供的方法无法满足子类需求时,对父类相同的方法(包括方法名和参数列表结构完全一致)覆盖。
子类覆盖的方法不能比父类的方法可见性小。父类私有的方法不会被重写(相当于不可见)。
子类返回值类型只能与父类一样或者是父类的子类和null,如果是基本数据类型,需要完全一致。
public class Sup {int a;int b;Sup speak() {return new Sub();}Sub speak(String words) {System.out.println("233");return new Sub();}}
public class Sub extends Sup {int b;Sub speak(String words) {super.speak(words);System.out.println("666");return new Sub();}
}
public class Test {public static void main(String[] args) {Sub sub = new Sub();sub.a = 1;sub.b = 2;sub.speak();sub.speak("");return;}
}
// 233
// 666
访问修饰符

多态
父类引用指向子类对象,产生了多态。(向上转型、里氏替换)
要求有继承关系,多态只能调用父类有的属性、方法,不能调用子类有的。
如果子类有父类方法的重写,则会调用子类的重写方法。
Pet pet = new Dog();
使用场景1:父类作为方法的形参实现多态,使得方法参数类型更宽泛(能用多个子类作为参数类型)
public class Animal {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void eat() {System.out.println("Animal eat what?");}public void feed(Animal animal) {animal.eat(); // 实际上是调用子类的eat重写方法}}
public class Dog extends Animal {public void eat() {System.out.println("Dog eat something!");}
}
public class Cat extends Animal {public void eat() {System.out.println("Cat eat fish!");}
}
public class Test {public static void main(String[] args) {Animal dog = new Dog();dog.eat();Animal cat = new Cat();cat.eat();}
}
// Dog eat something!
// Cat eat fish!
使用场景2:父类作为方法的返回值实现多态,使得方法返回不同的子类对象(能用多个子类作为返回值)
public class Animal {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void eat() {System.out.println("Animal eat what?");}public void feed(Animal animal) {animal.eat();}public Animal getAnimal(String type) {if (type.equals("Dog"))return new Dog();if (type.equals("Cat"))return new Cat();return null;}
}
public class Test {public static void main(String[] args) {Animal animal = new Animal();animal = animal.getAnimal("Cat");animal.eat();}
}
// Cat eat fish!
向下转型
父类无法调用子类的特有方法,需要强转(向下转型)后才能调用。要保证强转后的子类确实有这个方法。
public class Test {public static void main(String[] args) {Animal animal = new Cat();if (animal instanceof Cat) {Cat cat = (Cat) animal;cat.eatFish(); // Cat独有的方法}}
}
## 抽象类
不能被实例化的类,因为有些类过于顶层抽象,需要被继承存在才有现实意义,本身并不具备现实意义。使用`abstract`关键字修饰可以避免这个类被实例化。
常用于被子类继承,提供公共属性和方法;被作为多态的引用。
```java
public abstract class Animal {private String name;public void eat() {}
}
public class Test {public static void main(String[] args) {Animal animal = new Animal();}
}
会报错:Cannot instantiate the type Animal
抽象方法
抽象类中的方法本不该被调用(但因为多态,这些方法无法被删去,删了后方法无法被多态调用),而是需要子类实现后再调用子类的重写方法,因此设置为抽象方法。抽象方法只能存在于抽象类(或接口)中。
注意,如果子类也是抽象类,可以实现父类的抽象方法,但非抽象类子类需要实现所有的抽象方法。
public abstract class Animal {private String name;public abstract void eat();
}
public class Cat extends Animal {public void eat() {System.out.println("Cat eat fish!");}
}
静态成员和静态方法
用static关键字修饰的成员或方法,被修饰的称为静态成员(类成员)、静态方法(类方法)。
静态的成员、方法被所有的实例对象共享。
推荐用类名直接访问。
静态方法可以直接通过类名调用。
静态方法优先加载,因此静态方法不能调用非静态方法(未加载)。除非在静态方法中创建了一个类的实例,通过实例引用来调用。
静态方法中同样不能用this、super,因为此时还没有实例对象。
静态方法不能被重写、没有多态。子类可以调用到父类的静态方法,但这里应不理解为从父类继承的静态方法,而是直接引用了方法。子类与父类重名的静态方法只是独立的方法,而不是重写的方法。

public class Animal {private String name;static int count; // 静态成员变量public void setName(String name) {this.name = name;}public String getName() {return name;}public static int getCount() { // 静态方法return count;}}
public class Test {public static void main(String[] args) {Animal.count++; // 通过类访问静态成员System.out.println(Animal.getCount()); // 通过类调用类方法}
}
举例常用的静态方法Arrays.copyOf()、Arrays.sort()、Math.random()、Math.sqrt()
类加载过程
JVM首次使用某个类时,需通过CLASSPATH来找到该类的.class文件。
找到后将.class文件对类的描述信息加载到内存中,进行保存。(包名、类名、父类、属性、方法、构造方法)
加载时机:
- 创建对象
- 创建子类对象
- 访问静态属性
- 调用静态方法
- 反射:根据完全限定名主动加载类
Class.forName(className)
静态代码块
在类加载时优先执行的代码块,用于预备工作的执行。
类只加载一次,因此只会执行一次静态代码块。
静态代码块中可以使用静态成员和静态方法。
public class Test {public static void main(String[] args) {new Target();new Target();}
}// 静态成员变量被创建str
// 静态代码块执行
// 静态方法被调用
// 动态代码块执行(第二次创建对象时,类已经加载过,就不执行静态代码块内容)
// 构造方法执行
// 动态代码块执行
// 构造方法执行class Target {static String str = "str";static {System.out.println("静态成员变量被创建" + str);System.out.println("静态代码块执行");staticMethod();}{System.out.println("动态代码块执行");}Target() {System.out.println("构造方法执行");}static void staticMethod() {System.out.println("静态方法被调用");}
}
总结,静态的只属于类空间,非类控件(实例空间)的不允许被使用。
final关键字
final修饰类:不能被继承。
final修饰方法:不能被子类重写。
final修饰属性:不能被重新赋值(常量)。可以直接声明时赋值或者在构造函数/动态代码块中赋值(必须的,如果没有赋初值)。对于静态成员变量用final修饰,可以直接声明时赋值或者在静态代码块中赋值。
class Target {final int a;static final int b;Target() {a = 1; // 这里可以System.out.println("构造方法执行");}Target(int x){a = x; // 这里可以}{a = 1; // 这里可以System.out.println("动态代码块执行");}
}
class Target {static final int b;static {b = 2;System.out.println("静态代码块执行");}
}
public class Test {public static void main(String[] args) {final Target tg = new Target();tg = new Target(); // 用final修饰的对象变量不能被重新绑定,// 因为tg在栈中存储的对象地址已经是常量。}
}
接口
类似特殊的抽象类,没有构造方法,不能创建对象,只能定义公共静态常量和公共抽象方法。
public interface InterfaceTest {public static final double VERSION = 1.0;String platform = "Desktop"; // 默认是公共静态常量,可以省略修饰词public abstract void test();void demo(); // 默认是公共抽象方法,可以省略修饰词
}
public class SubInterface implements InterfaceTest {@Overridepublic void test() {System.out.println("SubInterface-test-method");}@Overridepublic void demo() {System.out.println("SubInterface-test-demo");}}
public class Test {public static void main(String[] args) {InterfaceTest it = new SubInterface();it.test();it.demo();}
}
与抽象类的不同点在于:没有代码块和构造方法、只能有公共静态常量和公共抽象方法。
与抽象类的相同点是:都能作为引用类型实现多态、不能实例化。
在Java 8之后,接口也可以包含默认方法(default修饰的方法)和静态方法(static修饰的方法)。默认方法是在接口中提供默认的方法实现,实现接口的类可以直接继承这个方法。静态方法是在接口中提供的静态方法,可以直接通过接口名调用。
接口表示能力
一个类无法继承多个父类,但可以通过实现多个接口的所有抽象方法(这也是为什么接口中必须是公共的抽象方法)来打到拥有不同能力的效果。
此外接口也能继承,而且是多继承,一个接口可以继承多个接口。
public interface ICode {void code();void debug();
}
public interface ISport {void run();void jump();
}
public class Student implements ICode, ISport {String can() {return "Student can ";}@Overridepublic void run() {System.out.println(can() + "run");}@Overridepublic void jump() {System.out.println(can() + "jump");}@Overridepublic void code() {System.out.println(can() + "code");}@Overridepublic void debug() {System.out.println(can() + "debug");}}
public class Test {public static void main(String[] args) {Student st = new Student();st.code();st.jump();}
}

常量接口:将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理,提高代码可读性。
接口表示标准
通过统一的标准实现低耦合插件。
package USB;public interface IUSB {void service();
}
package USB;public class USBFan implements IUSB {public void service() {System.out.println("A Fan Using USB!");}
}
package USB;public class USBDisk implements IUSB {public void service() {System.out.println("A Disk Using USB!");}
}
package USB;public class Computer {IUSB usb;
}
package USB;public class test {public static void main(String[] args) {Computer pc = new Computer();USBFan fan = new USBFan();// USBDisk disk = new USBDisk();pc.usb = fan; // 即插即用pc.usb.service();}
}
接口的标记作用
package USB;import java.io.Serializable;public class USBDisk implements IUSB,Serializable,Cloneable {public void service() {System.out.println("A Disk Using USB!");}
}
Serializable、Cloneable接口作为标记可以被虚拟机快速检测到,然后决定这对象能否序列化和克隆。
接口回调
为了使用尚未实现的抽象方法,采用接口回调处理。下面的doCall就是采用接口回调的设计。
package callback;public interface ICallback {void call();default void doCall() {call(); // 为什么没有实现call却可以调用?因为实现类一定会实现!可以假设已经实现了。}}
package callback;public class RealizeCallback implements ICallback {@Overridepublic void call() {System.out.println("实现了call方法");}}
package callback;public class RealizeCallback2 implements ICallback {@Overridepublic void call() {System.out.println("实现call的第二个方法");}}
package callback;public class Test {public static void main(String[] args) {ICallback cb = new RealizeCallback2();cb.doCall();}
}
Object类的方法
任何类包括java的接口都直接或间接继承了Object。
实例方法:
- getClass() 获取对象实例的类型
public class Animal {}
public class Cat extends Animal {}
public class Main {public static void main(String[] args) {Animal cat1 = new Animal();Animal cat2 = new Cat();System.out.println(cat1.getClass());System.out.println(cat2.getClass());System.out.println(cat2.getClass().getSimpleName());}
}
// class Animal
// class Cat
// Cat
- hashCode() 这个hash值是地址的映射,但存在哈希冲突,会有不同的地址值映射到同一个哈希值。
package Object;public class Test {public static void main(String[] args) {Animal cat1 = new Cat();Cat cat2 = (Cat) cat1;System.out.println(cat1.hashCode() + " -- " + cat2.hashCode());}
}
// 149928006 -- 149928006
package Object;public class Test {public static void main(String[] args) {System.out.println(new Animal().hashCode());System.out.println(new Animal().hashCode());String s1 = new String("test");String s2 = "test";System.out.println(s1.hashCode());System.out.println(s2.hashCode()); // 重写hash值,使两个一样的字符串值相同System.out.println(System.identityHashCode(s1)); System.out.println(System.identityHashCode(s2)); // 读取未被重写的hash值}
}// 41359092
// 149928006
// 3556498
// 3556498
// 713338599
// 168423058
- equals() 返回两个对象是否是统一对象
package Object;public class Animal {String name;public Animal(String name) {this.name = name;}@Overridepublic int hashCode() {return name.hashCode();}@Overridepublic boolean equals(Object obj) {if (obj.hashCode() == this.hashCode())return true;return false;}
}
package Object;public class Test {public static void main(String[] args) {Animal a = new Animal("cat");Animal b = new Animal("cat");System.out.println(a.hashCode());System.out.println(b.hashCode());System.out.println(a.equals(b));}
}// 98262
// 98262
// true
重写了两个方法,让原本不能equals的对象,在满足name相同时就相等。
- clone() 拷贝对象,浅拷贝。需要实现
Cloneable接口,调用super.clone()
package Object;public class Animal implements Cloneable {String name;public Animal(String name) {this.name = name;}public Animal clone() {Animal an = null;try {an = (Animal) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return an;}}
package Object;public class Test {public static void main(String[] args) {Animal a = new Animal("cat");Animal b = a.clone();System.out.println(b.name);}
}
// cat
成员内部类
https://www.bilibili.com/video/BV1994y1r7uV/?p=92&spm_id_from=pageDriver&vd_source=9cf1572a869a6a64c75ab4bdbe55f984