Java是完全面向对象的,必须熟悉OOP
才能够编写Java程序。
概念:类class、实例(对象)instance
由类构造(construct
)对象的过程称为创建类的实例(instance
)。
封装 encapsulation
有时称为数据隐藏,是与对象有关的一个重要概念。
从形式上看,封装只不过是将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式,
对象中的数据称为实例域(instance field
),操纵数据的过程称为方法(method
)。
对于每个特定的实例(对象)都有一组特定的实例域值。
这些值得集合就是这个对象的当前 状态(state
)。
类之间的关系
uses-a
)has-a
)is-a
)应该尽可能的把相互依赖的类减至最少。术语,让类之间的耦合度最小。
在Java程序设计语言中,使用构造器(constructor
)构造一个新的实例。
构造器是一种特殊的方法,用来构造并初始化对象。
用标准Java库中包含的Data类观察结果:
import java.util.Date; public class Test5 { public static void main(String[] args) { Date birthday = new Date(); // 用构造器构造一个对象 System.out.println(birthday); // Sat Oct 02 09:58:58 CST 2021 } }
对象与对象变量
对象:可以调用方法。
对象变量:在没有引用时(未被初始化),不可以调用方法。
import java.util.Date; public class Test5 { public static void main(String[] args) { Date birthday = new Date(); System.out.println(birthday); // Sat Oct 02 10:08:25 CST 2021 Date d; // 两个对象指向同一块内存区域 // d.toString(); // Error:(8, 9) java: 可能尚未初始化变量d d = birthday; System.out.println(d.toString()); // Sat Oct 02 10:08:25 CST 2021 } }
一定要认识到:一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。
在Java中,任何对象变量的值都是对存储在另外一个地方的一个对象的引用。
new
操作符的返回值也是一个引用。
所有的Java对象都存储在堆中。
当一个对象包含另一个对象变量时,这个变量依然包含着指向另一个堆对象的指针。
在Java中,必须使用clone
方法获得对象的完整拷贝。
更改器方法:访问并修改。
访问器方法:只访问,不修改。(更改器方法,访问器方法并没有明显的不同)
在一个源文件中,只能有一个共有类,但可以有任意数目的非共有类。
源文件名必须与public类的名字相同。
// Employee类 import java.time.LocalDate; public class Employee { // instance field 实例域 private String name; private double salary; private LocalDate hireDay; // constructor public Employee(String n, double s, int year, int month, int day) { name = n; salary = s; hireDay = LocalDate.of(year, month, day); } // a method 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; } }
// EmployeeTest类 public class EmployeeTest { public static void main(String[] args) { // fill the staff array with three Employee objects. Employee[] staff = new Employee[3]; staff[0] = new Employee("aa", 75000, 1987, 12, 15); staff[1] = new Employee("bb", 50000, 1989, 10, 1); staff[2] = new Employee("cc", 40000, 1990, 3, 17); // raise everyone's salary by 5% for(Employee e : staff) { e.raiseSalary(5); } // print out information about all Employee objects for(Employee e : staff) { System.out.println("name=" + e.getName() + ",salary=" + e.getSalary() + ", gireDay=" + e.getHireDay()); } } } /* 最终输出 name=aa,salary=78750.0, gireDay=1987-12-15 name=bb,salary=52500.0, gireDay=1989-10-01 name=cc,salary=42000.0, gireDay=1990-03-17 */
构造器总是伴随着new
操作符的执行被调用,而不能对一个已经存在的对象调用构造器来达到重新设置实例域的目的。
构造器特点:
new
操作一起调用隐式参数与显式参数
隐式参数:没有出现在方法声明中。
显式参数:出现在方法声明中。
例
定义:public void raiseSalary(double byPercent)
调用:number007.raiseSalary(5)
函数有两个参数。
第一个参数称为隐式(implicit
)参数,是出现在方法名前的Employee
类对象。
第二个参数位于方法名后面括号中的数值,这是一个显式(explicit
)参数。(有些人把隐式参数称为方法调用的目标或接收者。)
每一个方法中,关键字this
表示隐式参数。如果有隐式参数的话,推荐使用this.salary
代替salary
,这样可以更清楚的将实例域与局部变量明显的区分开来。
注意不要编写返回引用可变对象的访问器方法,这会破坏类的封装性。
如果需要返回一个可变对象的引用,应该首先对它进行克隆(clone
)。对象clone是指存放在另一个位置上的对象副本。
基于类的访问权限
一个方法可以访问所属类的所有的对象的私有数据。
class Employee { ... public boolean equals(Employee other) // 定义 { return name.equals(other.name); } } // 调用 if(harry.equals(boss)) ...
这个方法访问harry
的私有域,并且还访问了boss
的私有域。
这是合法的,其原因是boss
是Employee
类对象,而Employee
类的方法可以访问Employee
类的任何一个对象的私有域。
final
实例域
确保早每一个构造器执行之后,这个域的值被设置,并且在后面的操作中,不能够对它进行修改。
final
可以修饰非抽象类和非抽象类成员方法和变量
final类
不能被继承,没有子类,final类
中的方法默认是final
的final方法
不能被子类的方法覆盖,但可以被继承final成员变量
表示常量,只能被赋值一次,赋值后不再改变final
不能用于修饰构造方法static
关键字:属于类且不属于类对象的变量和函数。
静态域:用关键字static
修饰的类的成员变量。所有实例对象都共享这一块内存中的数据。
静态常量:用关键字static final
修饰的类的成员变量。在被赋值后就不可以修改。
静态方法:用关键字static
修饰的类的方法。不能向对象实施操作的方法,调用时应使用类名.静态方法名。
在下面两种情况下使用静态方法:
一个方法不需要访问对象状态,其所需参数都是通过显式参数提供(例如:Math.pow
)
一个方法只需要访问类的静态域(例如:Employee.getNextId
)
工厂方法:将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
main方法
:静态的main
方法将执行并创建程序所需要的对象。
参数传递分为两种:
按值调用(call by value
):表示方法接收的是调用者提供的值。
按引用调用(call by reference
):表示方法接收的是调用者提供的变量地址。
Java语言总是采用按值调用。
方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。
public static void tripleSalary(Employee x) { x.raiseSalary(200); }
当调用
harry = new Employee(...); tripleSalary(harry);
时,具体的执行过程为:
1)x被初始化为harry值的拷贝,这里是一个对象的引用。
2)raiseSalary 方法应用于这个对象应用。x和harry同时引用的那个Employee对象的薪金提高了200%。
3)方法结束后,参数变量x不再使用。当然,对象变量harry继续引用那个薪金增至3倍的雇员对象。
总结:Java中方法参数的使用情况