java的三大特性

面向对象三大特性: 封装继承多态

一、封装性

描述: 封装之前学习过方法,方法就是一种封装,在面向对象的封装性中,本质上也是讲方法的封装

  • 封装性:在面向对象中,不要直接调属性,而是通过set/get方法进行封装
  • 好处: 结构更清晰,复用性更强,安全性更强

封装步骤:

1.编写set/get方法,注意规范写法,set用于赋值,get用于取值

  • 按照项目中完整实体封装的写法,有多少属性,就有多少set/get
  • set方法规范:方法名为set+属性名首字母大写,参数名和属性名一致
  • get方法规范:方法名为get+属性首字母大写,返回属性值

2.属性私有化

//面向对象案例:张勇在吃饭
//分析:类-Student; 对象-张勇   属性-姓名,年龄   方法-吃
//问题:年龄为负数--- 会出现,程序没问题,数据不合理的情况
class Student{
	private String name;
	private int    age;  //属性私有化,外界不能调用,只能在当前类中使用
	
	public Student() {}
	public Student(String name,int age) {
		this.name = name;
		this.setAge(age); //this调方法
	}
	public void eat() {  //功能性的封装
		System.out.println(age+"岁的"+name+"正在吃饭~~");
	}
	
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	
	public void setAge(int age) { //数据(属性)的封装
		//注意:此处为了说明安全性,才加的判断;后续没有特殊说明,则直接赋值即可
		if(age<=0) { //如果参数有问题,则属性为默认18岁
			this.age = 18;
		}else { //如果大于0,则直接赋值
			this.age = age;
		}
	}
	
	public int getAge() {
		return age;
	}
}
public class Test1 {
	public static void main(String[] args) {
		Student zy = new Student();
		zy.setName("张勇");
		zy.setAge(-20);  //赋值
		
		//zy.age = -1;   //从源头上规避直接调属性
		System.out.println(zy.getAge());   //取值
		zy.eat();
		
		//2.编写带参构造
		Student ly = new Student("李勇",-30);
		ly.eat();
	}
}

二、继承性

理论描述

  • 生活中的继承: 子承父业,儿子继承了父亲的资源

  • 程序中的继承:子类继承父类的属性和方法

如何设定继承关系?什么类是子类?什么类是父类?

两个类满足“is a”的关系,就有继承关系。  
子类"is a" 父类,例如:猴子是动物,猴子是子类   动物是父类

找父类—父类有很多,怎么找直接父类

例如: 狗是动物,也是生物,也是物质
重合点(特征和行为接近)越多,越接近直接父类    
重合点越少,越接近Object类(后面会分析-老祖宗类)
例如:狗-姓名,年龄,毛色; 吃,摇尾巴,睡; 动物也类似;所以,动物类是狗类的直接父类

根据继承特点:只需将子类共性的部分抽取到父类即可;子类直接继承
继承作用:减少代码量,提高复用性;提高扩展性

继承案例

//面向对象案例出发:狗会跑,鸟会飞,鱼会游;同时它们都能吃能睡;属性都有姓名,年龄;狗和鸟有毛色
//注意:此处侧重点在于继承,暂时不去封装(后面写项目再封装)
//问题:冗余代码特别多;类与类之间完全独立
//找关系:狗是动物,鸟是动物,鱼是动物,都有同一个父类
class Animal{
	String name;
	int    age;
	public void eat() {
		System.out.println(name+"正在吃...");
	}
	public void sleep() {
		System.out.println(name+"正在睡...");
	}
}
class Dog extends Animal{  //Dog继承Animal
	String color;
	public void run() {
		System.out.println(name+"正在跑");
	}
}
class Bird extends Animal{ //Bird继承Animal
	String color;
	public void fly() {
		System.out.println(name+"正在飞");
	}
}
class Fish extends Animal{ //Fish继承Animal
	public void swim() {
		System.out.println(name+"正在游");
	}
}
public class Test1 {
	public static void main(String[] args) {
		Dog dog = new Dog();
		dog.name = "旺财"; //调父类的属性
		dog.color = "黄色"; //调自身独有属性
		dog.run();      //调自身独有方法
		dog.sleep();    //调父类方法
		System.out.println("--------------");
		
		Bird bird = new Bird();
		bird.name = "八哥";
		bird.fly();
		bird.eat();
		System.out.println("--------------");
		
		Fish fish = new Fish();
		fish.name = "小金";
		fish.swim();
		fish.sleep();
		
	}
}

继承特点

在继承中,没有多继承,但有多级继承

  • 多继承:有多个父类;
  • 多级继承:有父类,父类又有父类…
//案例:爷爷有1000万;爸爸有一辆跑车;儿子有一辆玩具车
class GrandFather{
	String name;
	public void haveMoney() {
		System.out.println(name+"拥有1000万");
	}
}
class Father extends GrandFather{ //多级继承
	public void haveCar() {
		System.out.println(name+"有一辆跑车");
	}
}
class Son extends Father/*,GrandFather*/{//没有多继承
	public void haveToy() {
		System.out.println(name+"有一辆玩具车");
	}
}
public class Test2 {
	public static void main(String[] args) {
		Father father = new Father();
		father.name = "大三"; //调爷爷类的属性
		father.haveMoney();  //调爷爷类的方法
		father.haveCar();    //调自身的方法
		//father.haveToy();  //不能调子类的方法
		System.out.println("===============");
		
		Son son = new Son();
		son.name = "小三";
		son.haveMoney();    //调爷爷类的方法
		son.haveCar();      //调父类的方法
		son.haveToy();      //调自身的方法
	}
}

不可继承性(扩)

  • 私有的成员(private)不能被继承
  • 构造方法没有继承性
  • 不同包的default权限,没有继承性

构造方法测试

//测试案例:构造方法没有继承性---测带参构造
class A{
	public A() {
		System.out.println("父类A的无参构造");
	}
	public A(int a) {
		System.out.println("父类A的带参构造");
	}
}
class B extends A{
}
public class Test1 {
	public static void main(String[] args) {
		//new B(6);  //构造方法没有继承性,不能调用父类A的带参构造
	}
}

权限测试

访问修饰符:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xoXnsDQO-1690793217796)(D:\笔记\千峰(1).assets\image-20230727144656658.png)]

测试:

//----------com.qf.d_quanxian包中的两个类----------
public class Animal { //实体类
	private String name;   //私有权限
	int  age;              //default权限
	protected String sex;  //保护权限
	public String love;    //公开权限
	
	public void eat() {
		System.out.println(name); //私有权限,在本类中可以使用
		System.out.println(age);  //默认权限,在本类中可以使用
		System.out.println(sex);  //保护权限,在本类中可以使用
		System.out.println(love); //公开权限,在本类中可以使用
	}
}

public class Test1 {   //测试类
	public static void main(String[] args) {
		Animal animal = new Animal();
		//System.out.println(animal.name); //私有权限,在同包不同类中不能使用
		System.out.println(animal.age);   //默认权限,在同包不同类中可以使用
		System.out.println(animal.sex);   //保护权限,在同包不同类中可以使用
		System.out.println(animal.love);   //公开权限,在同包不同类中可以使用
	}
}
//----------com.qf.e_quanxian2包中的两个类----------
public class Dog extends Animal {
	public void show() {
		//System.out.println(name);  //私有权限,在不同包子类中不能使用
		//System.out.println(age);   //default权限,在不同包子类中不能使用
		System.out.println(sex);   //保护权限,在不同包子类中可以使用
		System.out.println(love);   //保护权限,在不同包子类中可以使用
	}
}

public class Test1 {
	public static void main(String[] args) {
		Animal animal = new Animal();
		//System.out.println(animal.name); //私有权限,在不同包无继承关系中不能使用
		//System.out.println(animal.age); //默认权限,在不同包无继承关系中不能使用
		//System.out.println(animal.sex); //保护权限,在不同包无继承关系中不能使用
		System.out.println(animal.love); //公开权限,在不同包无继承关系中可以使用
	}
}

三、多态

一、多态

多态前提:必须要有继承或接口

程序中的多态:将子类对象当成父类看待,这就是多态;换句话说,父类引用指向子类对象,即形成多态

父类 自定义对象名 = new 子类();

例如:Animal an = new Dog(); //多态核心

多态应用:父类引用指向子类对象,即可调用父类的方法,不能调用子类独有的方法

应用案例
class Animal{
	public void eat() {
		System.out.println("动物正在吃...");
	}
}
class Dog extends Animal{
	public void bark() {
		System.out.println("旺财正在汪汪汪...");
	}
}
public class Test1 {
	public static void main(String[] args) {
		Animal animal = new Dog();  //多态核心
		animal.eat();   //父类引用可调用父类方法
		//当成父类看待,则调不了子类方法
		//animal.bark();  //父类引用不能调子类独有方法
	}
}

二、多态中的重写

  • 父类引用指向子类对象,优先调子类重写方法
  • 子类有重写方法,优先调子类方法
直接引用多态

直接引用多态的方式调用重写方法

//案例:将猫当成宠物看待,可调用宠物的吃的方法;如果猫有不同吃的行为,则优先调用
class Pet{
	public void eat() {
		System.out.println("宠物正在吃东西...");
	}
}
class Cat extends Pet{
	@Override
	public void eat() {
		System.out.println("猫正在吃...");
	}
}
public class Test2 {
	public static void main(String[] args) {
		Pet pet = new Cat(); //父类引用指向子类对象,优先调子类重写方法
		pet.eat(); //子类有重写方法,优先调子类方法
	}
}
传参多态

多态的好处:使程序的扩展性,可维护性更强

//案例:主人喂养宠物,猫,狗都是宠物,都有各自吃的行为
//分析:类-宠物类(父),猫类(子),狗类(子),主人类(第三方类); 方法-吃,喂养
//问题:两个宠物,就需要写两个喂养的方法;后面扩展更多宠物,则继续增加喂养方法
//面向对象设计原则:ocp原则-开闭原则
//o-open:对外部扩展的类持开放状态-例如可扩展很多宠物类(扩展性)
//c-close:对内部修改的代码持关闭状态-例如-主人喂养行为不要增加(维护性,灵活性)


class Pet{  //宠物类
	public void eat() { //吃
		System.out.println("宠物正在吃...");
	}
}
class Dog extends Pet{
	@Override
	public void eat() { //重写吃
		System.out.println("旺财正在吃...");
	}
}
class Cat extends Pet{
	@Override
	public void eat() { //重写吃
		System.out.println("加菲猫正在吃...");
	}
}
class Master{  //主人类
	//--------重载方法--------
	/*
	public void feed(Dog dog) {
		dog.eat();  //狗在吃
	}
	public void feed(Cat cat) {
		cat.eat();  //猫在吃
	}*/
	//传参实现的多态
	public void feed(Pet pet) {//Pet pet = new Dog(); 多态
		pet.eat(); //谁传给我,就调谁的 (不要看谁调的,要看谁传的)
	}
}
public class Test1 {
	public static void main(String[] args) {
		Master master = new Master();
		master.feed(new Dog());  //1.主人喂养狗
		master.feed(new Cat());  //2.主人喂养猫
	}
}
返回值多态

返回值多态: 调用方法返回子类对象,由父类引用接收;构成返回值多态

//案例:主人购买宠物;根据标识购买不同宠物:1.买鸟 2.买狗
//分析:类-主人类(第三方类);宠物类(父),鸟,狗(子) 方法:购买
class Pet{	
	public void eat() {
		System.out.println("宠物在吃东西");
	}
}
class Bird extends Pet{
	@Override
	public void eat() {
		System.out.println("鸟正在吃东西");
	}
}
class Dog extends Pet{
	@Override
	public void eat() {
		System.out.println("狗正在吃东西");
	}
}
class Master{
	public Pet bug(int type) {
		if(type==1) {
			return new Bird();
		}else if(type==2) {
			return new Dog();
		}else {
			return null;
		}
	}
}
public class Test1 {
	public static void main(String[] args) {
		Master master = new Master();
		Pet pet = master.bug(1); //返回子类对象;用父类Pet接收,形成多态
		pet.eat(); //调子类重写方法
	}
}

三、引用类型转换(扩展)

在基本类型中有类型转换:转的前提是类型要兼容;然后低类型可转高类型,高类型也能转低类型(强转)

在引用类型中,一样有类型转换:转换的前提是必须建立关系:父子关系(接口也可转)

在引用类型的转换中,有向上转和向下转两种

基本转换
  • 向上转—子类转父类,默认转(多态核心)

  • 向下转—父类转子类,强转

//父类Animal与子类Dog之间的相互转换:
class Animal{
}
class Dog extends Animal{
}
public class Test1 {
	public static void main(String[] args) {
		Animal animal = new Dog();  //向上转-默认转(多态核心)
		
		Dog dog = (Dog)animal;    //向下转-强转
	}
}
强转隐患及处理
//父类与子类之间的转换:
class Pet{ //父类
	
}
class Bird extends Pet{ //子类
	
}
class Pig extends Pet{  //子类
	
}
public class Test2 {
	public static void main(String[] args) {
		Pet pet = new Bird();
		//类型转换异常:Bird cannot be cast to Pig  鸟不能转成猪
		//Pig pig = (Pig) pet;  //向下转-强转(出现隐患)
		
		//可以使用instanceof处理类型转换的异常  instanceof-做判断的关键字
		// if (args instanceof type) {   args: 变量   type:类型
		
		if (pet instanceof Pig) {
			Pig pig = (Pig) pet;
			System.out.println("pet的本质类型是Pig");
		}else if(pet instanceof Bird) {
			Bird bird = (Bird)pet;
			System.out.println("pet的本质类型是Bird");
		} 
		
	}
}

扩展: instanceof

使用判定该对象是否属于该类(本类或子类)----- 返回true或false

语法:

对象  instanceof

结论:instanceof不是真实处理问题,而是规避异常

四、抽象类(扩展)

某些类具有某种方法,但不能具体实现,这样的方法叫抽象方法;所在的类就是抽象类。

例如:动物类(抽象类)----叫(抽象方法)

这样的抽象类我们无法具体化(不能实例化对象),可以交给子类具体化以及具体实现。

好处:

更自然地使用多态; 抽象方法可以当成模板来使用

抽象类细节说明:
1.抽象类能否具体化 不能
2.抽象类能否有构造方法 因为子类构造方法可以调:super()
3.有抽象方法的类一定是抽象类吗? 是的
4.抽象类是否必须有抽象方法? 可以没有抽象方法
5.抽象类是否可以有非抽象方法? 可以有
6.父类为抽象类,子类是否必须要重写抽象方法? 不是必须的,也可以将子类变为抽象类

报错:

The type Dog must implement the inherited abstract method Animal.bark()

报错处理方案:1.重写父类方法 2.把自身变抽象

直接引用多态

语法:

父类 自定义对象名 = new 子类();
//案例:动物类有一个叫的方法,可以交给狗类来完成
abstract class Animal{ //抽象类
	public abstract void bark();  //抽象方法--模板
	
	public Animal() {}  //可以有构造方法
	
	public void eat() {  //非抽象方法
		
	}
}

/*abstract*/ class Dog extends Animal{
	@Override
	public void bark() {
		System.out.println("大黄正在汪汪汪的叫...");
	}
	
	public void run() {
		System.out.println("大黄正在跑....");
	}
}
public class Test1 {
	public static void main(String[] args) {
		//Animal animal = new Animal();  //抽象类是不能具体化的
		Animal animal = new Dog();   //抽象类就是为多态而生  抽象类直接引用多态
		animal.bark();      //抽象类指向子类对象,可调用子类重写方法
		//animal.run();     //不可以调子类独有的方法
	}
}

结论: 后续使用继承的多态,基本都是抽象类实现多态;因为应用更明确,且父类方法不会太浪费

传参多态

语法:

自定义方法名(父类 自定义对象名)
//案例:主人喂养宠物,猫,猪都是宠物,都有各自吃的行为
//分析-宠物类(父),猫类(子),猪类(子),主人类(第三方类); 方法-吃,喂养:
abstract class Pet{ //抽象类
	public abstract void eat();  //抽象方法
}
class Cat extends Pet{
	@Override
	public void eat() {
		System.out.println("加菲猫正在吃...");
	}
}
class Pig extends Pet{
	@Override
	public void eat() {
		System.out.println("佩奇正在吃...");
	}
}
class Master{
	public void feed(Pet pet) { //传参多态
		pet.eat();
	}
}
public class Test2 {
	public static void main(String[] args) {
		Master master = new Master();
		master.feed(new Cat()); //主人喂猫
		master.feed(new Pig()); //主人喂猪
	}
}
返回值多态

语法参考模块:

	public 父类 自定义方法名(参数列表) {
		if(判定条件1) {
			return new 子类1();
		}else if(判定条件2) {
			return new 子类2();
		}else {
			return null;
		}
	}
//返回值多态:调用方法返回子类对象,由父类引用接收;构成返回值多态
//案例:小孩购买玩具;根据标识购买不同玩具:1.买鸟 2.买鱼
//分析:类-小孩类(第三方类);玩具类(父),鸟,鱼(子) 方法:购买
abstract class Toy{
	public abstract void start();
}
class Bird extends Toy{
	@Override
	public void start() {
		System.out.println("玩具鸟正在发射..");
	}
	
}
class Fish extends Toy{
	@Override
	public void start() {
		System.out.println("玩具鱼正在发射..");
	}
}
class Boy{
	public Toy buy(int type) {
		if(type==1) {
			return new Bird();
		}else if(type==3) {
			return new Fish();
		}else {
			return null;
		}
	}
}
public class Test3 {
	public static void main(String[] args) {
		Boy boy = new Boy();
		Toy toy = boy.buy(1);
		toy.start();
	}
}

扩展知识

this与super的使用与区别

  1. 子类对象创建时,父类的属性与方法会放在堆空间的哪?

    答:

    创建子类的对象时,父类的属性和方法也存储在堆内存中。子类对象在堆中有自己的内存空间,其中包括自己的属性和方法的内存,以及从父类继承的属性和方式的内存。这允许子类对象访问和使用父类的属性和方法。

  2. 调用构造方法做了哪些事?
    答:

    开辟空间、给属性赋值、调用构造方法实现、赋值给引用变量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值