java入门
快速入门
JDK,JVM,JRE的关系
jdk是Java开发工具包,其中包括编译工具(javac.exe)打包工具(jar.exe)等,也包括JRE
关系:jdk包含了jre,而jre又包含了jvm
总结:jdk用于java程序的开发,jre只能运行class文件,而没有编译功能
联系:JVM不能单独对class文件的执行,解释class的时候JVM需要调用JRE 的类库lib。在JRE目录里有两个文件夹bin和lib,可以认为bin里的就是 jvm,lib里的则是jvm工作所需要的类库,而jvm和 lib和起来就称为JRE。
数据类型
-
基本数据类型
- 整数类型:byte,short (2字节),int (4字节),long (8字节)
- 浮点数类型:float (4字节),double(8字节)
- 字符类型:char (2字节)
- 布尔类型:boolean
-
整型
只定义了带符号的整型
- byte:-128 ~ 127
- short: -32768 ~ 32767
- int: -2147483648 ~ 2147483647
- long: -9223372036854775808 ~ 9223372036854775807
-
浮点型
对于float类型,需要加上
f
后缀float
类型可最大表示3.4x1038,而double
类型可最大表示1.79x10308。 -
引用类型
- String 内部存储一个"地址",指向某个对象在内存的位置
-
常量
定义常量时,加上final修饰, 常量的变量名使用大写字母
-
var
关键字有些时候,类型的名字太长,写起来比较麻烦。例如:
StringBuilder sb = new StringBuilder();
这个时候,如果想省略变量类型,可以使用
var
关键字:var sb = new StringBuilder();
定义变量时,要遵循作用域最小化原则,尽量将变量定义在尽可能小的作用域,并且,不要重复使用变量名
字符和字符串
-
字符类型
字符类型
char
是基本数据类型,它是character
的缩写。一个char
保存一个Unicode字符char c1 = 'A'; char c2 = '中';
-
字符串类型
和char类型不同,字符串类型
String
是引用类型,我们用双引号"…………" 表示字符串。一个字符串可以存储0到任意个字符 -
字符串类型的不可变性
String 类使用fianl修饰不可被继承,不能被修改
数组类型
-
定义数据的方式 (数组属于引用类型,数组长度不可变)
// 数组 public class Main { public static void main(String[] args) { // 5位同学的成绩: int[] ns = new int[5]; System.out.println(ns.length); // 5 // 5位同学的成绩: int[] ns = new int[] { 68, 79, 91, 85, 62 }; int[] ns = { 68, 79, 91, 85, 62 }; System.out.println(ns.length); // 编译器自动推算数组大小为5 } }
流程控制
if条件判断
if (条件) {
// 条件满足时执行
}
if - else
// 条件判断
public class Main {
public static void main(String[] args) {
int n = 70;
if (n >= 60) {
System.out.println("及格了");
} else {
System.out.println("挂科了");
}
System.out.println("END");
}
}
if - else if - else
// 条件判断
public class Main {
public static void main(String[] args) {
int n = 70;
if (n >= 90) {
System.out.println("优秀");
} else if (n >= 60) {
System.out.println("及格了");
} else {
System.out.println("挂科了");
}
System.out.println("END");
}
}
判断引用类型相等
- 判断值类型相等使用
==
- 判断引用类是否相等,
==
表示"引用是否相等",或者说,是否指向同一个对象 - 需要判断引用类型的变量内容是否相等,必须使用
equals()
方法
// 条件判断
public class Main {
public static void main(String[] args) {
int n = 70;
if (n >= 90) {
System.out.println("优秀");
} else if (n >= 60) {
System.out.println("及格了");
} else {
System.out.println("挂科了");
}
System.out.println("END");
}
}
switch
// switch
public class Main {
public static void main(String[] args) {
int option = 99;
switch (option) {
case 1:
System.out.println("Selected 1");
break;
case 2:
System.out.println("Selected 2");
break;
case 3:
System.out.println("Selected 3");
break;
default:
System.out.println("Selected other");
break;
}
}
}
while
// while
public class Main {
public static void main(String[] args) {
int sum = 0; // 累加的和,初始化为0
int n = 1;
while (n <= 100) { // 循环条件是n <= 100
sum = sum + n; // 把n累加到sum中
n ++; // n自身加1
}
System.out.println(sum); // 5050
}
}
do while
// do-while
public class Main {
public static void main(String[] args) {
int sum = 0;
int n = 1;
do {
sum = sum + n;
n ++;
} while (n <= 100);
System.out.println(sum);
}
}
for 循环
// for
public class Main {
public static void main(String[] args) {
int sum = 0;
for (int i=1; i<=100; i++) {
sum = sum + i;
}
System.out.println(sum);
}
}
break 和 continue
- break 跳出当前循环
- continue 结束当初循环
面向对象
-
封装
private方法 不允许外部调用
// private method public class Main { public static void main(String[] args) { Person ming = new Person(); ming.setBirth(2008); System.out.println(ming.getAge()); } } class Person { private String name; private int birth; public void setBirth(int birth) { this.birth = birth; } public int getAge() { return calcAge(2019); // 调用private方法 } // private方法: private int calcAge(int currentYear) { return currentYear - this.birth; } }
-
this关键字:始终指向当前实例,因此通过
this.birth
就可以访问到当前实例的字段,如果没有命名冲突,可以省略this -
构造方法
每个类有默认的空参构造方法
class Person { public Person() { } }
如果显示定义了有参构造,那么空参构造也必须显示定义
-
方法重载 : 方法名相同,参数列表不同,返回值类型通常都是相同的
-
-
继承
extends
子类自动获得了父类的所有非私有字段和属性,严禁定义与父类重名的字段
-
java只允许一个class继承自一个类,因此,一个类有且仅有一个父类,只有
Object
类特色,它没有父类 -
protected
关键字可以把字段和方法的访问权限控制在继承树内部,一个protected
字段和方法可以被其子类,以及子类的子类访问 -
super
关键字表示父类(超类),子类引用父类的字段时,可以用super.fieldName
class Student extends Person { public String hello() { return "Hello, " + super.name; } }
-
任何
class
的构造方法,第一行语句必须是调用父类的构造方法,如果没有明确的调用父类方法,编译器会帮我们自动加一句super();
class Student extends Person { protected int score; public Student(String name, int age, int score) { super(); // 自动调用父类的构造方法 this.score = score; } }
-
子类不会继承父类的构造方法
-
阻止继承
-
正常情况下,只要某个class 没有被
final
修饰,那么任何类都可以从该class继承 -
从java15开始,运行使用
sealed
修饰class,并通过permits
明确写出能够从该class集成的子类名称例如,定义一个
Shape
类:public sealed class Shape permits Rect, Circle, Triangle { ... }
上述
Shape
类就是一个sealed
类,它只允许指定的3个类继承它。如果写:public final class Rect extends Shape {...}
是没问题的,因为
Rect
出现在Shape
的permits
列表中。但是,如果定义一个Ellipse
就会报错:public final class Ellipse extends Shape {...} // Compile error: class is not allowed to extend sealed class: Shape
原因是
Ellipse
并未出现在Shape
的permits
列表中。这种sealed
类主要用于一些框架,防止继承被滥用。sealed
类在Java 15中目前是预览状态,要启用它,必须使用参数--enable-preview
和--source 15
。 -
向上转型 把一个子类类型安全地变为父类类型的赋值,被成为向上转型
向上转型实际上是把一个子类型安全地变为更加抽象的父类型
Student s = new Student(); Person p = s; // upcasting, ok Object o1 = p; // upcasting, ok Object o2 = s; // upcasting, ok
-
向下转型 把一个父类类型强制转型为子类类型
-
instanceof : 判断示例是否是某种类型,避免向下转型失败
实际上判断一个变量所指向的实例是否是指定类型,或者这个类型的子类。如果一个引用变量为
null
,那么对任何instanceof
的判断都为falsePerson p = new Person(); System.out.println(p instanceof Person); // true System.out.println(p instanceof Student); // false Student s = new Student(); System.out.println(s instanceof Person); // true System.out.println(s instanceof Student); // true Student n = null; System.out.println(n instanceof Student); // false Person p = new Student(); if (p instanceof Student) { // 只有判断成功才会向下转型: Student s = (Student) p; // 一定会成功 }
-
子类和父类的关系是is,has关系不能用继承
-
-
-
-
-
多态
多态是指:针对某个类型的方法调用,其真正执行的方法取决于运行期间实际类型的方法
- 方法重写: 父类与子类方法名相同,返回值相同,
重写Object方法 : 因为所有的class最终都继承自object,而object定义了几个重要的方法:
toString()
:把instance输出为String
;equals()
:判断两个instance是否逻辑相等;hashCode()
:计算一个instance的哈希值。
class Person {
...
// 显示更有意义的字符串:
@Override
public String toString() {
return "Person:name=" + name;
}
// 比较是否相等:
@Override
public boolean equals(Object o) {
// 当且仅当o为Person类型:
if (o instanceof Person) {
Person p = (Person) o;
// 并且name字段相同时,返回true:
return this.name.equals(p.name);
}
return false;
}
// 计算hash:
@Override
public int hashCode() {
return this.name.hashCode();
}
}
调用super
在子类的重写方法中,如果要调用父类的被重写方法,可以通过super来调用
class Person {
protected String name;
public String hello() {
return "Hello, " + name;
}
}
class Student extends Person {
@Override
public String hello() {
// 调用父类的hello()方法:
return super.hello() + "!";
}
}
final 如果一个父类不允许子类对它的某个方法进行重写,那么可以使用final标记
抽象类 abstract
无法实例化的抽象类有什么用?
因为抽象类本身设计成只能被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此抽象方法实际上相当于定义了"规范"。
接口 interface
在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样多态就能发挥出威力,如果一个抽象类没有字段,所有方法全部都是抽象方法:就可以把该抽象类改写为接口:interface
。
接口中连字段都不能有
接口可以实现多个interface
接口与抽象类对比
abstract class | interface | |
---|---|---|
继承 | 只能extends一个class | 可以implements多个interface |
字段 | 可以定义实例字段 | 不能定义实例字段 |
抽象方法 | 可以定义抽象方法 | 可以定义抽象方法 |
非抽象方法 | 可以定义非抽象方法 | 可以定义default方法 |