1 面向对象
2 自定义类
形式:
class ClassName
{
field // 字段
constructor // 构造器(构造函数)
method // 方法
}
如:
class Employee
{
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String n, double s, int year, int month, int day) // Employee 的构造器
{
name = n; //注意不是 String name = n;
salary = s; // 注意不是 double salary = s;
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;
}
raiseSalary 方法有两个参数,第一个参数称为隐式参数,是 Employee 类型的对象 第二个参数是显式参数 byPercent
在每一个方法中,关键字 this
指示隐式参数:
事实上,关键字 this 的作用:
-
指示隐式参数的作用
-
调用同类其他构造器
public void raiseSalary(double byPercent)
{
double raise = this.salary * byPercent / 100;
this.salary += raise;
}
这样将实例字段和局部变量区分开来
注:参数变量会 遮蔽 同名的实例字段,用 this 可以标识出实例字段
2.1 final实例字段
将字段定义为 final,这样的字段必须在构造对象时初始化,且以后 不能再修改 这个字段(修饰不可变类的字段)
class Employee
{
private final name;
}
2.2 static实例字段
如果有100个 Employee 类对象,则有100个 id 实例字段,但是只有一个静态字段 nextId
class Employee
{
private static int nextId = 1;
private int id;
}
2.3 静态方法
静态方法是 不操作 对象的方法
调用一个静态方法,需要使用 类名.方法名()
的形式来调用
两种情况下可以使用静态方法:
-
方法不需要访问对象状态,因为它需要的所有参数都通过显式参数提供(例如 Math.pow)
-
方法只需要访问类的静态字段
关于静态方法,可以在不创建类的实例的情况下被调用,比如 Math 类,Math 类没有构造器,所有的方法都是静态方法
适合使用静态方法的类:
-
工具类,如 Math 类
-
常量类,如 Math.PI
-
工厂方法,如 LocalDate 类
-
全局配置类
2.4 工厂方法
例如 LocalDate 和 NumberFormat 类使用静态 工厂方法 构造对象
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFormatter = NumberFormat.getPercentInstance();
double x = 0.1;
System.out.println("currencyFormatter.format(x)"); // prints $0.10
System.out.println("percentFormatter.format(x)"); // prints 10%
NumberFormat 类不使用构造器来创建对象的原因:
-
无法为构造器命名(构造器的名字要和类相同,但是希望有两个不同的名字)
-
无法改变所构造对象的类型(工厂方法返回 DecimalFormat 类的对象,继承自 NumberFormat)
2.5 方法参数
在程序设计语言中,关于参数传递到方法的两种形式:
-
按值调用(call by value):表示方法接收的是值
-
按引用调用(call by reference):表示方法接收的是变量的位置
在 Java 中 总是 使用 按值调用,方法不能修改传递给他的任何参数变量的内容
Java 对于方法参数:
-
方法不能修改基本数据类型的参数
-
方法可以改变对象参数的状态
-
方法不能让一个对象参数引用一个新对象
2.6 重载 (overload) 和 覆盖 (override)
有些类有多个构造器,例如:
var messages_1 = new SrtingBuilder();
var messages_2 = new SrtingBuilder("hello!");
重载 (overload):多个方法有相同的方法名,但有不同的参数
Java 允许重载任何方法,要完整地描述一个方法,需要指定 方法名 和 参数类型,这叫做方法的 签名
例如 String 类有4个 indexOf 的方法:
indexOf(int)
indexOf(int, int)
indexOf(String)
indexOf(String, int)
但是返回类型不是签名的一部分,即不能有两个有相同名字和相同参数类型却有不同的返回类型的方法
Java 不支持运算符重载
覆盖(override):子类方法实现,覆盖了父类方法
class Parent {
public void someMethod() {
// 父类方法实现
}
}
class Child extends Parent {
@Override
public void someMethod() {
// 子类方法实现,覆盖了父类方法
}
}
2.7 参数名
1.在编写很小的构造器时,对参数的命名:(尽量不要这样写)
public Employee(String n, double s)
{
name = n;
salary = s;
}
2.对于单个字母的参数名影响可读性,所以在每个参数前加上"a":
public Employee(String aName, double aSalary)
{
name = aName;
salary = aSalary;
}
3.因为参数变量会 遮蔽 同名的实例字段,所以可以用 this
来标识实例字段:
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
2.8 调用另一个构造器
如果构造器的 第一个语句 形如 this(...)
,这个构造器将调用同类的另一个构造器:
public Employee(double s)
{
// calls Employee(String, double)
this("Employee #" + nexId, s);
nextId++;
}
这样可以提高代码的重用性
2.9 初始化块
初始化实例字段的方法:
-
在构造器中设置值
-
在声明中赋值
-
初始化块
初始化块:在一个类的声明中,可以包含任意的代码块,构造这个类的对象时候,这些块就会执行
class Employee
{
private static int nextId;
private int id;
private String name;
private double salary;
{
id = nextId;
nextId++;
}
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
public Employee()
{
name = "";
salary = 0;
}
}
无论使用哪个构造器构造对象,id 字段会在对象初始化块中初始化
当调用一个构造器时,按照如下顺序进行:
-
如果构造器第一行调用了另一个构造器,则基于所提供的参数执行第二个构造器
-
否则, a) 所有实例字段初始化为默认值(0, false 或 null) b) 按照在类声明中出现的顺序,执行所有字段初始化方法和初始化块
-
执行构造器主体代码
还有一种静态初始化块:
private static Random generator = new Random();
static
{
nextId = generator.nextInt(10000);
}
3 包
3.1 静态导入
导入包的时候加上static,就可以不用前缀使用静态方法和静态字段
import static java.lang.Math.*;
public class StaticImport {
public static void main(String[] args) {
int radius = 5;
double area = PI * pow(5, 2);
System.out.println(area);
}
}