面向对象高阶

面向对象进阶

1.封装

封装的意义在于保护或者防止代码(数据)被无意中破坏。保护成员属性,不让类以外的程序直接访问和修改。

封装原则:隐藏对象的属性和实现细节,仅对外公开访问方法,并且控制访问级别。

/**
 * 封装
 * @author 孟祥宽
 *
 */
public class Demo1 {

	public static void main(String[] args) {
		Person1 person = new Person1();
		person.setName("孟祥宽");
		person.setAge(20);
		person.say();
	}
}
class Person1{
	private String name;
	private int age;
    
    
	// 构造方法
    public Person1() {
        this.("默认名字",1);
        System.out.println("默认名字:" + this.name + "\n默认年龄:" + age);
    }
    public Person1(String name, int age) {
        this.name = this.setName(name);
        this.setAge(age);
    }
	// set和get方法
	public String setName(String name) {
		return this.name = name;
	}
	public String getName() {
		System.out.println("名字:" + this.name);
		return this.name;
	}
	public int getAge() {
		System.out.println("年龄:" + this.age);
		return age;
	}
	public void setAge(int age) {
		if(age > 150 || age < 0) {
			this.age = 1;
		} else {
			this.age = age;
		}
	}
	public void say() {
		System.out.println("姓名:" + name + "\n年龄:" + age);
	}
}

运行结果:image-20211107154512038

1.1 this关键字

在Java基础中,this关键字是一个重要的概念。使用this关键字可以完成以下操作:

  • 调用类中的属性
  • 调用类中的方法或者构造方法
    • 在一个构造函数中,调用另一个构造方法时,调用的代码,必须编写在构造方法的第一行
  • 表示当前对象
public String setName(String name) {
    /**
    * 这个this表示对象
    */
		return this.name = name;
 }

public Person1() {
    /**
    * 表示调用类的构造方法
    */
        this.("默认名字",1);
        System.out.println("默认名字:" + this.name + "\n默认年龄:" + age);
}

1.2 static关键字

static表示“静态”的意思,可以用来修饰成员变量和成员方法。static的主要作用在于创建独立于具体对象的域变量或者方法,即不用依赖于对象,使用类就可以调用

简单理解

被static关键字修饰的方法或者变量不需要依赖对象来进行访问,只要类被加载,就可以通过类名去进行访问。并且不会因为对象的多次创建而在内存中创建多份数据。

image-20211107193538497

重点:

  1. 静态成员在类加载的时候加载并初始化。
  2. 无论一个类存在多少个对象,静态的属性,永远在内存中只有一份(可以理解为所有对象共用)。
  3. 在访问时,静态不能访问非静态,非静态可以访问静态。
public class Demo3 {
	public static void main(String[] args) {
		Person3.show();
		System.out.println();
		Person3 p = new Person3("孟祥宽");
		p.showPerson();
		Person3 p2 = new Person3("mxk");
		p2.showPerson();
	}
}
class Person3 {
	private static int index;
	private String name;
	
	public Person3() {}
	public Person3(String name) {
		index ++;
		this.setName(name);
	}
	public static int getIndex() {
		return index;
	}
	public static void setIndex(int index) {
		Person3.index = index;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	// 静态方法
	public static void show() {
		System.out.print(index + ".用户:");
		// this.getName(); -> static在类加载的时候加载,可能没有创建对象,所以不能用this.
		// getName(); -> 同理,普通方法依赖于对象,静态方法里不能调用非静态方法.
	}
	@SuppressWarnings("static-access")
	public void showPerson() {
		this.show();
		System.out.println(this.name);
	}
	
}

运行结果:image-20211107200506939

2.继承

继承就是子类继承父类的特征(属性)和行为(方法),使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

继承的限制:Java中只有单继承,多重继承没有多继承。C++有多继承。一个孩子只能有一个爹。

public class Student extends Person {// Student 继承 Person(父类)
}

image-20211118144505980

2.1 super关键字

/**
	 * 通过super:可以访问父类的构造方法
	 * 				调用super的构造方法要把super()放在第一行
	 * 				不存在同时调用this和super方法
	 * 			可以访问父类的属性
	 * 			可以访问父类的方法
	 * @param name
	 * @param age
	 * @param subject
	 */
	public Student(String name, int age, String subject) {
		super(name,age);// 父类的构造函数
		index++;
		this.setSubject(subject);
	}

2.2 重写 override

重写的规则:

  1. 参数列表必须完全与被重写方法的相同;
  2. 返回类型必须完全与被重写方法的返回类型相同;
  3. 访问权限不能比父类中被重写的方法的访问权限更低。比如:父类用public 子类不能用protected;
  4. 父类的成员方法只能被它的子类重写;
  5. 声明为static、private的方法不能被重写,但是能够被再次声明;

面试题:重写与重载的区别?

答案:

  1. 发生的位置。
    • 重载:一个类中
    • 重写:子父类中
  2. 参数列表限制。
    • 重载:必须不同
    • 重写:必须相同
  3. 返回值类型。
    • 重载:与返回值类型无关
    • 重写:必须一致
  4. 访问权限。
    • 重载:与访问权限无关
    • 重写:子的方法权限必须不能小于父的方法权限
  5. 异常处理。
    • 重载:与异常无关
    • 重写:可以更精准范围更小但是不能抛出新的异常

2.3 final关键字

  1. 用于修饰属性、变量;

    • 变量成为了常量,无法对其在此进行赋值。

    • final修饰的局部变量,只能赋值一次(可以先声明后赋值)。

    • final修饰的成员属性,必须在声明时赋值。

      • ※全局常量:public static final

        常量的命名规范:由一个或多个单词组成,单词语单词之间必须使用下滑线隔开,单词中所有字母大写。

        示例:BASE_INFO

  2. 用于修饰类;

    • 不可以被继承
  3. 用于修饰方法;

    • 不可以被子类重写
public static void main(String[] args) {
		final int a = 5;// 变量成为了常量,无法对其再次进行赋值
		/* 报错:The final local variable a cannot be assigned. It must be blank and not using a compound assignment
		 翻译:无法指定最终的局部变量a。它必须为空且不使用复合赋值
		*/
		// a = 21;
		System.out.println(a);
		final int a1;
		a1 = 20;
		System.out.println(a1);
	}

3.多态

对象的多种表现形式。子类就是父类的一种形态。

重写(override)和重载(overload)也是多态的体现。

  • 重写:子父类的方法多态性
  • 重载:一个类的方法多态性
/**
 * 抽象类
 * @author 孟祥宽
 *
 */
public abstract class Person {

	// 姓名
	private String name;
	// 年龄
	private int age;
	
	// 构造方法
	public Person() {
		this("默认姓名", 18);
	}
	public Person(String name, int age) {
		this.setAge(age);
		this.setName(name);
	}
	// getter 和  setter 方法
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		if(age > 150 || age < 0) {
			System.err.println("年龄错误!默认为18岁");
			this.age = 18;
		}else {
			this.age = age;
		}
	}
	// show 方法
	public abstract void show();
}

/**
 * Student 类
 * @author 孟祥宽
 *
 */
public class Student extends Person {

	// 学校
	private String school;
	
	// 构造方法
	public Student() {
		super();
		this.school = "默认学校";
	}
	public Student(String name, int age, String school) {
		super(name, age);// 父类的构造方法
		this.setSchool(school);
	}
	// getter setter
	public String getSchool() {
		return school;
	}
	public void setSchool(String school) {
		this.school = school;
	}

	/**
	 * 重写show方法
	 */
	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("姓名:" + super.getName() + ";\n年龄:" + super.getAge() + ";\n学校:" + this.school + ".");
	}
	/**
	 * 重载
	 */
	public String show(String name, int age, String school) {
		this.setAge(age);
		this.setName(name);
		this.setSchool(school);
		System.out.println("姓名:" + super.getName() + ";\n年龄:" + super.getAge() + ";\n学校:" + this.school + ".");
		return "姓名:" + super.getName() + ";\n年龄:" + super.getAge() + ";\n学校:" + this.school + ".";
	}
}

import com.kaikeba.test.pojo.*;

/**
 * 测试类
 * @author 孟祥宽
 *
 */
public class Test {
	public static void main(String[] args) {
		Student student = new Student();
		student.show();
		System.out.println("------------------");
		student.show("多态",15,"java");
		System.out.println("------------------");
		Student student2 = new Student("孟祥宽",25,"长春理工大学");
		student2.show();
		System.out.println("------------------");
		Nurse nurse = new Nurse("小梦",18,"沈阳工学院");
		nurse.show();
		System.out.println("------------------");
		Driver driver = new Driver("大梦",40,"新东方");
		driver.show();
		System.out.println("------------------");
		// 父类引用子类
		Person person = new Student("小吴",24,"大连理工");
		person.show();
		System.out.println("------------------");
		Person person2 = new Nurse("小李",30,"白城市医院");
		person2.show();
	}
}


运行结果:image-20211118233130359

3.1 对象类型转换

/**
*
* 父类
*/
public class Person {}

/**
*
* 子类
*/
public class Student extends Person {} // 继承

/**
*
* 子类
*/
public class Nurse extends Person {} // 继承

/**
*
* 测试类
*/
public class Test {
    public static void main(String[] args) {
        // 向上转换 即 子类转换成父类
        Person person = new Student();
        // 向下转换 即 父类转换成子类 需要强转
        Student student = (Student) person;
        Person person2 = new Nurse();
        // ClassCastException异常
        Student student2 = (Student) person2;// 此时会报错 因为 person2 引用的是Nurse类 不能请转成Student类 
    }
}

3.2 instanceof关键字

判断某个对象是否是指定类的实例。

public static void main(String[] args) {
		// 父类引用子类
		Person person = new Student("小吴",24,"大连理工");
		person.show();
		say(person);
		System.out.println("------------------");
		Person person2 = new Nurse("小李",30,"白城市医院");
		person2.show();
	}
	public static void say(Person person) {
		// 判断传入的对象是此对象那种形态
		String str = person instanceof Student ? "Student":"";
		System.out.println("这是一个" + str);
	}

运行结果:image-20211119103306221

posted @ 2021-11-19 10:35  雨溟  阅读(39)  评论(0)    收藏  举报