目录
构造器
概述
构造器,也称之为构造方法。(constructor)
构造器的作用:创建对象
说明:
1. 如果没有显示的定义了类的构造器的话,则系统默认提供一个空参的构造器
2. 定义构造器的格式:权限修饰符 类名(形参列表){}
public class Person {
//属性
String name;
int age;
public Person(){
System.out.println("构造器执行了。。。");
}
//方法
public void eat(){
System.out.println("吃东西");
}
}
public class PersonTest {
public static void main(String[] args) {
//创建类的对象:new + 构造器
Person p1 = new Person();
p1.eat();
}
}
使用细节
构造器,也称为构造方法,constructor。
构造器的作用:
- 创建对象
- 初始化对象的信息
细节说明:
- 如果没有显式的定义类的构造器的话,则系统会默认提供一个空参的构造器
- 定义构造器的格式:权限修饰符 类名(参数列表){}
- 一个类中可以定义多个构造器,彼此构成重载
- 一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
- 一个类中至少会有一个构造器
总结属性赋值的过程
到目前为止,我们掌握的属性赋值的方式有:
- 默认初始化
- 显式初始化
- 构造器中初始化
- 通过“对象.方法”或者“对象.属性”的方式赋值
如果在一个类中用到了上面的赋值方式,那先后顺序是什么呢? 就是上面写好的顺序。
public class UserTest {
public static void main(String[] args) {
User u1 = new User();
u1.setAge(10);
System.out.println(u1.getAge());
}
}
class User{
private String name;
private int age = 1;
public User(){
age = 5;
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
public void setAge(int a){
age = a;
}
public int getAge(){
return age;
}
}
JavaBean
- JavaBean是一种Java语言写成的可重用组件
- 所谓JavaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共构造器
- 有属性,且有对应的get、set方法
/*
* JavaBean
*/
public class Customer {
private int id;
private String name;
public Customer(){
}
public void setId(int i){
id = i;
}
public int getId(){
return id;
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
}
this关键字
概述
- 在java中,this关键字比较难理解,它的作用和词义很接近
- 它在方法内部使用,即这个方法所属对象的引用
- 它在构造器内部使用,表示该构造器正在初始化的对象
- this表示当前对象,可以调用类的属性、方法和构造器
- 什么时候使用this?
- 当在方法内需要用到调用该方法的对象时,就用this。具体的:我们可以用this来区分局部变量和属性。比如:this.name = name;
简单来说,this表示的就是当前这个对象。
this调用属性
public class User {
private String name;
private int age;
public User(){
}
public User(String name, int age){
//构造器中这个this表示的就是当前正在要创建的对象
//这里的this就是为了区分局部变量和成员变量的
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
//这个this表示的就是 谁调用我这个方法,this就是谁!!!
//这里的this就是为了区分局部变量和成员变量的
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
this调用构造器
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
//这里的this是调用有一个String类型参数的构造器,且使用this调用构造器的话,
//这行代码必须写在第一行!!!
this(name);
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
this调用方法
public class Person {
private String name;
private int age;
public Person() {
}
public void method1(){
System.out.println("method1...");
//这个this指的就是调用当前对象的method2方法,其实是可以省略的!
this.method2();
}
public void method2(){
System.out.println("method2...");
}
继承
- 概述
现实生活中的继承是什么样的?有什么好处?
Java中的继承是什么样的?有什么好处?
可以发现继承的好处:
- 减少了代码的冗余,提高了代码的复用性
- 便于功能的扩展
- 为之后多态的使用提供了前提
继承的使用
- 继承的格式:class A extends B{ }
A:子类、派生类、subclass
B:父类、超类、基类、superclass
- 体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的结构:属性、方法。
- 特别地,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构,只是因为封装性的影响,使得子类不能直接调用父类的结构而已
子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的扩展。子类和父类的关系,不同于子集和集合的关系。
简单案例
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("人吃饭!");
}
public void sleep(){
System.out.println("人睡觉!");
}
}
public class Teacher extends Person{
private int teachAge;
public int getTeachAge() {
return teachAge;
}
public void setTeachAge(int teachAge) {
this.teachAge = teachAge;
}
public void teach(){
System.out.println("老师在讲课!");
}
}
public class Student extends Person{
private int score;
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public void study(){
System.out.println("学生在学习!");
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
//调用父类继承过来的方法
student.eat();
student.sleep();
//调用自己的方法
student.study();
//调用父类继承的方法给属性设置值
student.setName("张三");
student.setAge(20);
//调用自己的方法给属性赋值
student.setScore(98);
}
}
继承性的再说明
Java中继承性的规定:
1. 一个类可以被多个类继承
2. Java中类的单继承性:一个类只能有一个父类
3. 子父类是相对的概念
4. 子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
5. 子类继承父类以后,就获取了直接父类和所有间接父类中声明的属性和方法
通过案例演示上面的各个规定。
Object类的理解
定义一个Student类,创建一个Student类的对象s1,我们可以发现可以通过s1调用好多我们没有在Student类中写的方法,为什么呢?
- 如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
- 所有的类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
- 意味着,所有的java类具有java.lang.Object类中声明的功能
方法的重写
- 定义:在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
- 要求:
- 子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表
- 子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型
- 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限
- 子类不能重写父类中声明为private权限的方法
- 子类方法抛出的异常不能大于父类被重写方法的异常
案例
public class Person {
public void eat(){
System.out.println("人吃东西!");
}
}
public class Student extends Person{
@Override
public void eat() {
System.out.println("学生喜欢吃零食!");
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.eat();
}
}
特殊地,如果父类中有两个方法A和B,其中A方法中调用了B方法,但是子类中重写了B方法,当我们创建子类对象后,调用A方法,这时候A方法中调用的B实际上是子类重写后的B方法。
super关键字
概述
super是超或者父的意思,使用super就可以调用父类中的属性、方法、构造器。
super调用属性和方法
使用super关键字可以在子类中调用父类的属性和方法
public class Person {
private String name;
private int age;
int id = 123456;
public Person() {
}
public Person(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void eat(){
System.out.println("人吃东西!");
}
public void run(){
System.out.println("人在跑步!");
}
}
public class Student extends Person{
int id = 1001;
public void showId(){
System.out.println("id = " + id);
//使用super调用父类中的属性
System.out.println("super.id = " + super.id);
}
@Override
public void eat() {
System.out.println("学生吃零食!");
super.eat(); //使用super调用父类中的方法
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.showId();
student.eat();
}
}
super调用构造器
- 我们可以在子类的构造器中显式的使用super()调用父类的构造器
- super()必须在方法的首行
- 之前this()调用构造器也必须在首行,所以this()和super()是二选一的
- 在构造器的首行,如果没有显式的写this()或者super(),则默认调用父类的空参构造器,也就是默认是super()
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Student extends Person{
private String major;
public Student() {
//这里默认其实是 super()
}
public Student(String name, int age, String major) {
//调用父类中的构造器
super(name, age);
this.major = major;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student("张三", 25, "软件工程");
}
}
子类实例化的全过程
子类对象实例化的全过程:
- 从结果上来看:(继承性)
- 子类继承父类以后,就获取了父类中声明的属性和方法
- 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
- 从过程上来看:
- 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类的结构,子类对象才可以考虑进行调用。
明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建了一个对象,即为new的子类对象。(其实我们只是在子类中调用了父类构造器,并不是new 父类构造器() )
其实也就是说,当我们创建一个子类对象的时候,它会从最顶级的父类一级一级的往下走,最后走的才会走完它自己的构造器。
多态
- 多态是面向对象语言的特征
- 多态:也就是一个事物的多种形态
- Java中的多态:父类的引用指向子类的对象
- 多态的使用:虚拟方法调用,也就是说:有了对象的多态性后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
总结:编译,看左边;运行,看右边
- 多态的使用前提:1. 类的继承 2. 方法的重写
注意:属性是不存在覆盖之说的,对象的多态性只适用于方法,不适用于属性。
案例:
public class Person {
private String name;
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void eat(){
System.out.println("人在吃东西!");
}
public void run(){
System.out.println("人在跑步!");
}
}
public class Student extends Person{
private int score;
public Student() {
super();
}
public Student(String name, int score) {
super(name);
this.score = score;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
//重写父类的方法
@Override
public void eat() {
System.out.println("学生在吃东西!");
}
//重写父类的方法
@Override
public void run() {
System.out.println("学生在跑步!");
}
}
public class Teacher extends Person{
private int teachAge;
public Teacher() {
super();
}
public Teacher(String name, int teachAge) {
super(name);
this.teachAge = teachAge;
}
public int getTeachAge() {
return teachAge;
}
public void setTeachAge(int teachAge) {
this.teachAge = teachAge;
}
//重写父类的方法
@Override
public void eat() {
System.out.println("老师在吃东西!");
}
//重写父类的方法
@Override
public void run() {
System.out.println("老师在跑步!");
}
}
public class Test {
// public void method(Student student){
// student.eat();
// student.run();
// }
//
// public void method(Teacher teacher){
// teacher.eat();
// teacher.run();
// }
public void method(Person person){
//这里就用到了多态,具体person这个引用是指向哪个子类对象,
//那这里就调用哪个子类的方法
person.eat();
person.run();
}
public static void main(String[] args) {
Test test = new Test();
test.method(new Student());
test.method(new Teacher());
}
}
虚拟方法的调用理解
- 正常的方法调用
Person p = new Person();
p.getInfo();
Student s = new Student();
s.getInfo();
- 虚拟方法调用(多态情况下)
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
Person p = new Student();
p.getInfo(); //调用Student类的getInfo()方法
- 编译时类型和运行时类型
编译时p为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。---动态绑定