-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
名词解释
- JDK:Java Development Kit
- JRE:Java Runtime Environment
- JSR规范:Java Specification Request
- JCP组织:Java Community Process
JSR是一系列的规范,从JVM的内存模型到Web程序接口,全部都标准化了。而负责审核JSR的组织就是JCP
- RI:Reference Implementation
- TCK:Technology Compatibility Kit
通常来说,RI只是一个“能跑”的正确的代码,它不追求速度; 一般大家都会选择一个有竞争力的商用或开源产品(TCK)
安装JDK
从Oracle的官网下载最新的稳定版JDK
检查是否安装
java -version
# java version "16.0.2" 2021-07-20
# ...SDK命令
java:这个可执行程序其实就是JVM,运行Java程序,就是启动JVM,然后让JVM执行指定的编译后的代码;javac:这是Java的编译器,它用于把Java源码文件(以.java后缀结尾)编译为Java字节码文件(以.class后缀结尾);jar:用于把一组.class文件打包成一个.jar文件,便于发布;javadoc:用于从Java源码中自动提取注释并生成文档;jdb:Java调试器,用于开发阶段的运行调试。
基本语法
Java规定,某个类定义的public static void main(String[] args)是Java程序的固定入口方法,因此,Java程序总是从main方法开始执行。
eg: Hello.java, java的文件名要保持和类名相同。
public class Hello {
public static void main(String[] args) {
// System.out.println("Hello, world!");
for (String arg : args) {
if ("-version".equals(arg)) {
System.out.println("v 1.0");
break;
}
}
}
}运行: java Hello.java
基本数据类型、字符串、数组
基本数据类型
- 整数类型:
byte(1byte),short(2byte),int(4byte),long(8byte) - 浮点数类型:
float(4byte),double(8byte) - 字符类型:
char(2byte) - 布尔类型:
boolean
demo
public class Hello {
public static void main(String[] args) {
// System.out.println("hello world");
// byte:-128 ~ 127
// short: -32768 ~ 32767
// int: -2147483648 ~ 2147483647
// long: -9223372036854775808 ~ 9223372036854775807
int i1 = 1;
int i2 = 2_000_000_000; // 加下划线更容易识别
int i3 = 0xff0000; // 十六进制表示的16711680
int i4 = 0b1000000000; // 二进制表示的512
int i5 = (100 + 200) * (99 - 88); // 3300
int i6 = 12345 / 67; // 184 两个整数相除只能得到结果的整数部分
int i7 = 12345 % 67; // 12345÷67的余数是17
// +=,-=,*=,/=,++(自加),--(自减),<<(左移),>>(右移,负数高位1不变),>>>(不管符号位, 右移后高位总是补0),&(按位与),|(按位或),~(非运算,01互换),^(异或), ...
int i8 = 2147483640 + 15; // -2147483641 数据溢出,不会报错, 解决方法:用long类型
int i9 = (int) 12.3; // 12 强制类型转换,浮点数的小数部分会被丢掉, 四舍五入可以使用: int i9 = (int) (d + 0.5)
// 要显示一个字符的Unicode编码,只需将char类型直接赋值给int类型即可:
int i10 = 'A'; // 字母'A'的Unicodde编码是65
int i11 = '中'; // 汉字'中'的Unicode编码是20013
// long型的结尾需要加L
long l1 = 9000000000000000000L;
// 对于float类型,需要加上f后缀
float f1 = 3.14f;
float f2 = 3.14e38f; // 科学计数法表示的3.14x10^38
double d1 = -1.79e308;
double d2 = 4.9e-324; // 科学计数法表示的4.9x10^-324
double d3 = 1.0 / 10;
double d4 = 1 - 9.0 / 10;
// 由于浮点数存在运算误差,所以比较两个浮点数是否相等常常会出现错误的结果。eg: d3 == d4, 解决办法: Math.abs(x - y) < 0.00001,可以认为相等
int n = 5;
// 类型提升
double d5 = 1.2 + 24.0 / n; // 6.0, 参与运算的两个数其中一个是整型,那么整型可以自动提升到浮点型
// 溢出 整数运算在除数为0时会报错,而浮点数运算在除数为0时,不会报错,但会返回几个特殊值
// NaN表示Not a Number
// Infinity表示无穷大
// -Infinity表示负无穷大
double d6 = 0.0 / 0; // NaN
double d7 = 1.0 / 0; // Infinity
double d8 = -1.0 / 0; // -Infinity
// 强制转型
// char使用单引号(')
char a = 'A';
char zh = '中';
// \\u+Unicode编码来表示一个字符, 注意是十六进制:
char c3 = '\u0041'; // 'A',因为十六进制0041 = 十进制65
char c4 = '\u4e2d'; // '中',因为十六进制4e2d = 十进制20013
// boolean值 !, >, >=, <, <=, ==, !=, &&, ||
boolean isZero = false; // false
boolean isNonZero = !isZero; // true
boolean isGreater = 5 > 3 && 2 > 1; // true
boolean isTrue = 3 > 2 ? true : false; // 三元运算符
// 字符串类型(引用类型)
String s1 = ""; // 空字符串,包含0个字符
// \是转义字符: \" 表示字符", \' 表示字符', \\ 表示字符\, \n 表示换行符, \r 表示回车符, \t 表示Tab, \\u#### 表示一个Unicode编码的字符
String s2 = "abc\"xyz"; // 包含7个字符: a, b, c, ", x, y, z
String s3 = "ABC\n\u4e2d\u6587"; // 包含6个字符: A, B, C, 换行符, 中, 文
// 字符串连接
String s4 = "hello" + " " + "world" + "!";
// 多行字符串
String s5 = "first line \n"
+ "second line \n"
+ "end";
String s6 = """
SELECT * FROM
users
WHERE id > 100
ORDER BY name DESC"""; // 共同的空格会被去掉; """ 写在下一行将代表最后加了一个 \n
// 空值null
String s7 = null; // s1是null
String s8; // 没有赋初值值,s2也是null
String s9 = s1; // s3也是null
String s10 = ""; // s4指向空字符串,不是null
// 数组 数组所有元素初始化为默认值,整型都是0,浮点型是0.0,布尔型是false;数组一旦创建后,大小就不可改变。
int[] ns = new int[5];
ns[0] = 1;
// System.out.println(ns.length); // 5
// 索引超出范围,运行时将报错, eg: ns[5] = 1
// 编译器自动推算数组大小
int[] ns2 = new int[]{68, 79, 91, 85, 62};
int[] ns3 = {68, 79, 91, 85, 62};
// 遍历数组
for (int i = 0; i < ns.length; i++) { // 遍历下标
int tmpN = ns[i];
// System.out.println(n);
}
for (int tmpN : ns) { // 遍历元素
// System.out.println(tmpN);
}
// 多维数组
int[][] ns4 = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 常量
// 定义变量的时候,如果加上final修饰符,这个变量就变成了常量
final double PI = 3.14; // PI是一个常量
// var关键字
var sb = new StringBuilder(); // 编译器自动推断 等价于 StringBuilder sb = new StringBuilder();
}
}类
一个Java源文件可以包含多个类的定义,但只能定义一个public类,且public类名必须与文件名一致。如果要定义多个public类,必须拆到多个Java源文件中。
public class Main {
public static void main(String[] args) {
var ming1 = new Person();
ming1.setName("ming1");
ming1.age = 20;
// ming1.setAge(-1);
var ming2 = new Person("ming2", 21);
// System.out.println(ming1.getName() + ", age: " + ming1.age); // ming1, age: 20
// System.out.println(ming2.getName() + ", age: " + ming2.age); // ming2, age: 21
// ming1.hello("zhangsan"); // Hello, zhangsan!
// ming1.hello("zhangsan", 15); // Hi, zhangsan!!!
// ming1.hello("zhangsan", 20); // Hello, zhangsan!!!
// Student > Person > Object
var stu1 = new Student(10);
Person stu2 = new Student(10);
Student stu3 = new Student(10);
Object stu4 = new Student(10);
stu1.name = "ABC";
// System.out.println(stu1.hello()); // Hello, ABC
// System.out.println(stu1 instanceof Person); // true
// System.out.println(stu1 instanceof Student); // true
// stu1.run(); // Student.run
}
}
//final class Person { // 用final修饰的类不能被继承
class Person {
// private String idCard; // private 类型的属性和方法,在子类中无法访问到
// public final String name = "Unamed"; // 用final修饰的字段在初始化后不能被修改, 但可以在构造方法中初始化final字段
protected String name;
protected int age;
protected String gender = "UnKnow"; // 提供默认值
public static int number; // 静态字段,访问: Person.number
public static void setNumber(int value) { // 静态方法
number = value;
}
/**
* 构造函数:构造方法的名称就是类名,没有参数限制
* 没有在构造方法中初始化字段时,引用类型的字段默认是null,数值类型的字段用默认值,int类型默认值是0,布尔类型默认值是false
*/
// 类构造方法1
public Person() {
// this("NoName", 0); // 构造函数内可以调用其他构造函数
}
// 类构造方法2
public Person(String name, int age) {
this.name = name;
// this.age = age;
this.setAge(age);
}
public void setName(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("invalid name");
}
this.name = name;
}
public String getName() {
return this.name;
}
public void setAge(int age) {
if (age < 0 || age > 100) {
throw new IllegalArgumentException("invalid age value");
}
this.age = age;
}
/**
* 方法重载 -- 方法名相同,但各自的参数不同, 方法重载的返回值类型通常都是相同的。
*/
public void hello(String name) {
System.out.println("Hello, " + name + "!");
}
public void hello(String name, int age) {
if (age < 18) {
System.out.println("Hi, " + name + "!!!");
} else {
System.out.println("Hello, " + name + "!!!");
}
}
// public final String run() { // 用final修饰的方法不能被Override
public void run() {
System.out.println("Person.run");
}
}
/**
* 继承
*/
class Student extends Person {
private int score;
public Student(int score) {
// 如果用户没有手动调用super, 则编译器自动调用父类的构造方法, 如下:
// super();
this.score = score;
}
public Student(String name, int age, int score) {
super(name, age); // 调用父类的构造方法Person(String, int)
this.score = score;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public String hello() {
// super关键字表示父类(超类)
return "Hello, " + super.name;
// return "Hello, " + this.name;
// return "Hello, " + name;
}
// 覆盖父类方法 (Override和Overload不同的是,如果方法签名不同,就是Overload,Overload方法是一个新方法;如果方法签名相同,并且返回值也相同,就是Override。)
// 注意:方法名相同,方法参数相同,但方法返回值不同,也是不同的方法。在Java程序中,出现这种情况,编译器会报错。
// 加上@Override可以让编译器帮助检查是否进行了正确的覆写。希望进行覆写,但是不小心写错了方法签名,编译器会报错。 但是@Override不是必需的。
@Override
public void run() {
// super.run(); // 这里也支持调用父类的方法
System.out.println("Student.run");
}
}
/**
* 抽象类Person2 -- 抽象类无法实例化对象
*/
abstract class Person2 {
public abstract void run();
}
class Student2 extends Person2 {
// 这里子类必须实现抽象类方法
@Override
public void run() {
System.out.println("Student.run");
}
}
/**
* 接口
* 一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个interface
* eg: class Student implements Person, Hello {}
*/
interface Person3 {
// 接口的静态字段; 因为interface是一个纯抽象类,所以它不能定义实例字段。但是,interface是可以有静态字段的,并且静态字段必须为final类型:
// public static final int MALE = 1;
// public static final int FEMALE = 2;
// 实际上,因为interface的字段只能是public static final类型,所以我们可以把这些修饰符都去掉,上述代码可以简写为:
// 编译器会自动加上public static final:
int MALE = 1;
int FEMALE = 2;
void run();
String getName();
}
class Student3 implements Person3 {
private String name;
public Student3(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(this.name + " run");
}
@Override
public String getName() {
return this.name;
}
}
// 一个interface可以继承自另一个interface
interface Hello {
void hello();
}
interface Person4 extends Hello {
void run();
String getName();
}
// default方法
interface Person5 {
String getName();
// 接口方法默认实现
default void run() {
System.out.println(getName() + " run");
}
}参考资料:
Metadata
Metadata
Assignees
Labels
No labels
