学习课程:廖雪峰的官方网站:https://www.liaoxuefeng.com/
詹姆斯·高斯林(James Gosling)
这三者之间有啥关系呢?
Java源码本质上是一个文本文件,我们需要先用javac把Hello.java编译成字节码文件Hello.class,然后,用java命令执行这个字节码文件:
包命名:com.hello.world
类、接口命名:HelloWorld
方法命名:helloWorldHelloWorld
变量命名:helloWorldHelloWorld
常量命名:HELLO_WORLD
Java基本数据类型占用的字节数:
特别注意:同一个数的不同进制的表示是完全相同的,例如15=0xf=0b1111。
对于float类型,需要加上f后缀。
float f1 = 3.14f;
float f2 = 3.14e38f; // 科学计数法表示的3.14x10^38
float f3 = 1.0; // 错误:不带f结尾的是double类型,不能赋值给float
double d = 1.79e308;
char a = 'A';
引用类型最常用的就是String字符串:
String s = "hello";
C++中引用和指针的区别:https://blog.csdn.net/smartgps2008/article/details/90648015
定义变量的时候,如果加上final修饰符,这个变量就变成了常量:
final double PI = 3.14; // PI是一个常量
有些时候,类型的名字太长,写起来比较麻烦。如果想省略变量类型,可以使用var关键字,以下两者等效。
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
在Java的计算表达式中,运算优先级从高到低依次是:
()
! ~ ++ –
* / %
+ -
<< >> >>>
&
|
+= -= *= /=
举个栗子:
浮点数0.1在计算机中就无法精确表示,因为十进制的0.1换算成二进制是一个无限循环小数,很显然,无论使用float还是double,都只能存储一个0.1的近似值。
double x = 1.0 / 10;
double y = 1 - 9.0 / 10;
// 观察x和y是否相等:
System.out.println(x); // x=0.1
System.out.println(y); // y=0.09999999999999998
所以要特别注意浮点数的运算,判断浮点数相等用“==”判断不靠谱,正确的方法是利用差值小于某个临界值来判断。比如:
double x = 1 - 9.0 / 10; // x=0.09999999999999998
// 不要使用==直接判断,错误写法:if (x == 0.1) {}
// 而是使用差值小于某个临界值来判断
if (Math.abs(x - 0.1) < 0.00001) {}
\ | char | String |
---|---|---|
定义 | 字符 | 字符串 |
类型 | 基本类型 | 引用类型 |
描述 | “持有”某个数值 | “指向”某个对象 |
符号使用 | ‘’ | “” |
可以用数组变量.length获取数组大小:
int[] ns = new int[] { 68, 79, 91, 85, 62 };
System.out.println(ns.length); // 编译器自动推算数组大小为5
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // 创建Scanner对象
System.out.print("Input your name: "); // 不换行输出
String name = scanner.nextLine(); // 读取一行输入并获取字符串
System.out.println("Input your age: "); // 换行输出
int age = scanner.nextInt(); // 读取一行输入并获取整数
System.out.printf("Hi, %s, you are %d\n", name, age); // 格式化输出
}
}
String s1 = "hello";
String s2 = "HELLO".toLowerCase();
System.out.print(s1 == s2); // false
System.out.print(s1.equals(s2)); // true
使用switch要留意需不需要使用break,注意千万不要漏写break。
int[] ns = { 1, 4, 9, 16, 25 };
// 使用for循环
for (int i=0; i<ns.length; i++) {
System.out.println(ns[i]);
}
// 使用for each循环
for (int n : ns) {
System.out.println(n);
}
int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
// 遍历:方法一
for (int i=0; i<ns.length; i++) {
int n = ns[i];
System.out.println(n);
}
// 遍历:方法二
for (int n : ns) {
System.out.println(n);
}
//直接打印,不能得到想要的结果
System.out.println(ns); // 直接打印数组变量,得到的是数组在JVM中的引用地址。类似 [I@7852e922
// 调用Java标准库
import java.util.Arrays;
System.out.println(Arrays.toString(ns));
// 其他方法
Arrays.sort(ns);
// 构造方法用于初始化实例
Person p = new Person("Xiao Ming", 15);
Person p2 = new Person("Xiao Ming"); // 自动匹配到构造方法
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(int age) {
this.name = "xiaoming";
this.age = age;
}
public Person(String name) {
this(name, 18); // 调用另一个构造方法Person(String, int)
}
}
class Hello {
public void hello() {
System.out.println("Hello, world!");
}
public void hello(String name) {
System.out.println("Hello, " + name + "!");
}
}
Java使用extends关键字来实现继承:
class Person {
private String name;
private int age;
...
public String getName() {...}
public void setName(String name) {...}
...
}
class Student extends Person {
// 不要重复定义name和age字段/方法,
private int score; // 在父类基础之上新增字段和方法
...
public int getScore() { … }
public void setScore(int score) { … }
}
子类自动获得了父类的所有字段,严禁定义与父类重名的字段!
在父类与子类之间,方法名,参数列表,返回类型都相同,是被允许的。这种现象称为方法的重写。
在OOP的术语中,我们把Person称为超类(super class),父类(parent class),基类(base class),把Student称为子类(subclass),扩展类(extended class)。
继承树:
如果父类没有默认的构造方法,子类就必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。(栗子)
小结:
Override
子类对父类方法进行重写时,方法类型、方法名、方法参数必须都相同相同
class Person {
public void run() {
System.out.println("Person.run");
}
}
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
抽象类和接口的对比如下:
\ | abstract class | interface |
---|---|---|
继承 | 只能extends一个class | 可以implements多个interface |
字段 | 可以定义实例字段 | 不能定义实例字段 |
抽象方法 | 可以定义抽象方法 | 可以定义抽象方法 |
非抽象方法 | 可以定义非抽象方法 | 可以定义default方法 |
实例字段在每个实例中都有自己的一个独立“空间”,但是静态字段只有一个共享“空间”,所有实例都会共享该字段。
调用实例方法必须通过一个实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用。
public class Main {
public static void main(String[] args) {
Person.setNumber(99);
}
}
class Person {
public String name;
public int age;
// 定义静态字段number:
public static int number;
// 静态方法
public static void setAge(int value) {
this.age = value;
}
}
如下两实例对象:
class Outer {
class Inner {
// 定义了一个Inner Class
}
}