0%

Java 基础

1 Java 概述

2014 Java8

2017 Java9

Java11 LTS版

2 Java 程序设计环境

2.1 Java 术语

  • JDK: Java开发工具(包含JRE)

  • JRE: Java运行环境

  • Java SE (Standard Edition) 标准版本:用于桌面或者简单服务器应用的Java平台

  • Java EE (Enterprise Edition) 企业版本:用于复杂服务器应用的Java平台

  • Java ME (Micro Edition) 微型版本:用于小型设备的Java平台

  • NetBeans:Oracle公司的集成开发环境

2.2 命令行工具编译运行

javac 是一个 Java 编译器,将文件 Welcome.java 编译成 Welcome.class,java 程序启动 Java 虚拟机,虚拟机执行类文件中的字节码

1
2
javac Welcome.java
java Welcome

注意:

  • java Welcome,java 区分大小写
  • javac 需要文件名(Welcome.java),而运行程序时,只需指定类名,不需要带扩展名 .java.class

常见错误及解决方法:

https://docs.oracle.com/javase/tutorial/getStarted/problems/index.html

2.3 JShell

Java 9 以上,交互式窗口

那么何时开始使用IDE工具呢?标准是:如果你还离不开这个IDE工具,那么你就不能使用这个IDE工具;只有当你十分清楚在IDE工具里单击每一个菜单,单击每一个按钮……IDE工具在底层为你做的每个细节时,才可以使用IDE工具!

3 Java 基本程序设计

3.1 简单结构

1
2
3
4
5
public class FirstSample {
public static void main(String[] args){
System.out.println("Hello World!");
}
}

注意:

  • Java 区分大小写
  • Java 类名必须以字母开头,后面跟字母和数字的组合,长度基本没有限制,但不能用 Java 保留字。采用驼峰命名法(camel case),CamelCase
  • 源代码文件名必须与公共类名字相同,并用 .java 为拓展名
  • main 方法必须声明为 public

3.2 注释

1
2
3
//
/**/
/**开头,*/结束,多用于类的注释

3.3 数据类型

强类型语言,8中基本类型

3.3.1 整型

类型 字节数 取值范围
int 4 -2147483648~2147483647(刚超过20亿)
short 2 -32 768~32 767
long 8 -9223372036854775808~9223372036854775807
byte 1 -128~127
  • long 类型后面有一个后缀 L 或 l (40000000L)。十六进制 0x 或 0X。八进制前缀 0
  • Java 7 开始加上前缀 0b 或 0B 可以写二进制数。另外还可以为数字变量加上下划线,如 1_000_000 表示 100 万

3.3.2 浮点类型

类型 字节数 有效位数
float 4 6~7位
double 8 15位
  • float 类型后有一个后缀 F 或 f ,没有后缀的浮点数值默认为 double 类型

  • 三个特殊的浮点数值:
    正无穷大、负无穷大、NaN(不是一个数字)
    Double.POSITIVE_INFINITY、Double.NEGATIVE_INFINITY、Double.NaN分别表示这三个特殊值
    ==注意判断时不能直接 == ,使用 Double.isNaN 方法判断==

  • ==浮点值不适用于无法接受舍入误差的金融计算==
    如,System.out.println(2.0-1.1)将打印出 0.8999999999999999 而不是 0.9,这是因为浮点数值采用二进制系统表示,在其中无法精确地表示分数 1/10,对于这种情况换用 BigDecimal

3.3.3 char 类型

最好不要使用这种类型

1个java的char字符并不完全等于一个unicode的字符。char采用的UCS-2编码,是一种淘汰的UTF-16编码,编码方式最多有65536种,远远少于当今Unicode拥有11万字符的需求。java只好对后来新增的Unicode字符用2个char拼出1个Unicode字符。导致String中char的数量不等于unicode字符的数量。

3.3.4 boolean 类型

boolean 只有两个值 true 和 false

  • java中 true != 1,false != 0

3.4 变量与常量

Java 10 开始,可以使用 var 关键字而无需指定类型

1
2
var a = 12;
var c = "hello";

3.4.1 常量

final 指示常量,表示这个常量只能被赋值一次。习惯上,常量名使用全大写。

3.4.2 枚举类型

1
public enum Size {SMALL, MEDIUM, LARGE}

3.5 运算符

image-20200807171257887

3.6 字符串

字符串用双引号括起来

  1. 子串

    1
    2
    String greeting = "Hello";
    String s = greeting.substring(0, 3);//左闭右开思想
  2. 拼接

    1
    String message = "Hello" + "World";

    连在一起,用界定符分隔,用 join 方法:

    1
    2
    String all = String.join("/", "S", "M", "L", "XL");
    // all is string "S/M/L/XL"

    Java 11 还提供了一个 repeat 方法:

    1
    2
    String repeated = "Java".repeat(3);
    // "JavaJavaJava"比较字符串是否相等
  3. 判断字符串相等

    1
    "Hello".equals(greeting);
  4. 构建字符串

    1
    2
    3
    4
    StringBuilder builder = new StringBuilder();//Java5+
    builder.append(ch);
    builder.append(str);
    String myString = builder.toString();

3.7 输入与输出

3.7.1 读取输入

首先构造一个与 System.in 相关联的 Scanner 对象,然后使用 Scanner 对象的方法进行读取

Scanner 对象属于 java.util 包,==不属于 java.lang 包的,都需要 import==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.*;

/**
* This program demonstrates console input.
* @version 1.10 2004-02-10
* @author Cay Horstmann
*/
public class InputTest
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);

// get first input
System.out.print("What is your name? ");
String name = in.nextLine();

// get second input
System.out.print("How old are you? ");
int age = in.nextInt();

// display output on console
System.out.println("Hello, " + name + ". Next year, you'll be " + (age + 1));
}
}

Java 6 引入 Console 类读取密码:

1
2
3
Console cons = System.console();
String username = cons.readLine("Username: ");
char[] passwd = cons.readPassword("Password: ");//安全起见,返回密码存放在字符数组中。密码处理完成后,应马上用一个填充值覆盖字符数组元素

3.7.2 格式化输出

System.out.print 和 C 语言的语法差不多

格式化打印时间:

1
2
3
4
System.out.printf("%tc", new Date());
//周六 8月 08 18:12:27 CST 2020

Y 年 m 月 d 日 H 时 M 分 S 秒

一个参数可被多次使用,添加索引方式,索引必须以 % 开头,以 $ 结束

1
2
System.out.printf("%1$s %2$tB %2$tm, %2$tY", "Due date: ", new Date());
//Due date: 八月 08, 2020

也可以使用 < 知识前面的参数将被再次使用

1
System.out.printf("%s %tB %<tm, %<tY", "Due date: ", new Date());

3.7.3 文件输入输出

3.8 大数

BigInteger 和 BigDecimal 可以分实现任意精度的整数和浮点数的计算

valueof 方法将普通的数值转化成大数:

1
BigInteger a = BigInteger.valueOf(100);

不能使用算法运算符(+和*)处理大数,而需要使用 add 和 multipy 方法

4 对象与类

4.1 访问控制符

  • private —— 仅对本类可见
  • public —— 对外部完全可见
  • protected —— 对本包和所有子类可见
  • 默认,不需要修饰符 —— 对本包可见

4.2 包

用命令行编译运行带包的 java 文件层,需要在上一层且带上包名

1
2
javac inheritance\ManagerTest.java
java inheritance.ManagerTest

5 继承

5.1 类,超类和子类

已存在的类被称为超类(superclass)、基类(base class)或父类(parent class);新类被称为子类(subclass)、派生类(derived class)或孩子类(child class)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.horstmann.corejava;

// the classes in this file are part of this package

import java.time.*;

// import statements come after the package statement

/**
* @version 1.11 2015-05-08
* @author Cay Horstmann
*/
public class Employee
{
private String name;
private double salary;
private LocalDate hireDay;

public Employee(String name, double salary, int year, int month, int day)
{
this.name = name;
this.salary = salary;
hireDay = LocalDate.of(year, month, day);
}

public String getName()
{
return name;
}

public double getSalary()
{
return salary;
}

public LocalDate getHireDay()
{
return hireDay;
}

public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}
1
2
3
public class Manager extends Employee{
……
}

覆盖方法

1
2
3
4
5
public double getSalary(){
double baseSalary = super.getSalary();
//不能直接用salary,因为它在Employee类中是private的
return baseSalary+bonus;
}

子类构造器

1
2
3
4
public Manager(String name, double salary, int year, int month, int day){
super(name, salary, year. month, day);
bonus = 0;
}

5.1.1 阻止继承:final 类和方法

阻止派生 Executive 类的子类

1
2
3
public final class Executiv extends Manager{
……
}

同样设置方法为 final ,子类就不可以覆盖这个方法

1
2
3
4
5
public class Employee{
public final String getName(){
return name;
}
}

5.1.2 抽象类

抽象类声明抽象的方法,具体实现是在子类。抽象类方便方法调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package abstractClasses;

public abstract class Person
{
public abstract String getDescription();
private String name;

public Person(String name)
{
this.name = name;
}

public String getName()
{
return name;
}
}

public class Student extends Person
{
public String getDescription()
{
return "a student majoring in " + major;
}
}

5.2 Object:所有类的超类

可以用 Object 类型变量引用任何类型的对象。具体操作时需要进行强制类型转换

1
2
Object obj = new Employee("Hacker", 3500);
Employee e = (Employee)obj;

只有基本类型不是对象,所有数组类型,包括基本类型的数组都拓展了 Object 类

5.3 泛型数组列表

Java 中允许在运行中确定数组的大小,更简单的方法是使用 ArrayList 类,类似于数组,但在添加或删除元素的时候,能自动调整数组容量。

尖括号中类型参数不允许是基本类型

1
2
3
4
5
6
7
8
9
ArrayList<Employee> staff = new ArrayList<Employee>();
//or
ArrayList<Employee> staff = new ArrayList<>();
//java10 可以使用 var
var staff = new ArrayList<Employee>();

staff.add(new Employee("Hacker",...));
staff.set(i, harry);
Employee e = staff.get(i);

5.4 反射

https://javasec.org/javase/Reflection/Reflection.html

6 接口、lambda 表达式与内部类

6.1 接口

接口不是类,而是对希望符合这个接口的类的一组需求。

Comparable 接口代码:

1
2
3
public interface Comparable<T>{
int compareTo(T other);
}

在接口中所有方法都自动是 public,不过在实现的时候,必须把方法声明为 public

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Employee implements Comparable<Employee>
{
/**
* Compares employees by salary
* @param other another Employee object
* @return a negative value if this employee has a lower salary than
* otherObject, 0 if the salaries are the same, a positive value otherwise
*/
public int compareTo(Employee other)
{
return Double.compare(salary, other.salary);
}
}

为什么不把接口设计为抽象类呢?

一个类智能继承一个类但能实现多个接口。

Java 设计者选择了不支持多重继承,因为其会让语言变得非常复杂或者降低效率。

6.2 lambda 表达式

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package lambda;

import java.util.*;

import javax.swing.*;
import javax.swing.Timer;

/**
* This program demonstrates the use of lambda expressions.
* @version 1.0 2015-05-12
* @author Cay Horstmann
*/
public class LambdaTest
{
public static void main(String[] args)
{
var planets = new String[] { "Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune" };
System.out.println(Arrays.toString(planets));
System.out.println("Sorted in dictionary order:");
Arrays.sort(planets);
System.out.println(Arrays.toString(planets));
System.out.println("Sorted by length:");
Arrays.sort(planets, (first, second) -> first.length() - second.length());
System.out.println(Arrays.toString(planets));

var timer = new Timer(1000, event ->
System.out.println("The time is " + new Date()));
timer.start();

// keep program running until user selects "OK"
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}

6.3 代理

动态代理(Dynamic Proxy)的机制:可以在运行期动态创建给定接口的新类。

https://javasec.org/javase/DynamicProxy/DynamicProxy.html

7 异常处理

https://www.runoob.com/java/java-exceptions.html