面向对象概念
面向对象
编程思想
概念:建立解决问题的思路,即编程思想
常见的编程思想
-
面向过程: 自顶向下,逐步求精,注重解决问题的过程,将解决问题分为一个一个的步骤,只要按照步骤执行就一定能解决问题
-
面向对象: 分析解决问题需要的哪些功能,而哪些对象具有这种功能;注重对象之间的配合调用
问题: 回家
面向过程: 拿着地图,分析回家需要经过哪些路口,每条路上走多远,遇到路口往哪儿拐,一步一步就走到家了
面向对象:只需要调用出租车(对象)的载客功能,由出租车送我们回家
注意:面向对象与面向过程并不是完全对立!面向对象是在面向过程的基础上实现的
面向对象
认识对象
什么是对象?
Java眼中的对象: 一切客观存在的事物都是对象!世界就是由对象组成的!—万物皆对象
例如:水杯、桌子、电脑、空气、错误等等都是对象
程序中的对象: 内存中的一块存储空间,用来存储对现实对象的关注的部分,从而代表现实中的对象
-
对象的组成:
-
特征(属性): 有什么
-
行为(方法): 干什么
注意:有时候,一个对象的属性可能也是一个对象;对象的调用者可能也是一个对象
例如:硬盘是电脑的属性,硬盘本身也是对象;程序员使用电脑开发,程序员也是对象 -
-
对象间的关系
-
一个对象继承了另一个对象 is a 例如:狗是一个动物
-
小对象组成大对象 has a 例如:电脑由硬盘、cpu组成
-
一个对象使用另一个对象 use a 例如:程序员使用电脑
-
认识类
类与对象的关系
-
类是对象的模板,对象是类的实例
-
类是人们对一系列相同相似事物(现实中的对象)的认识,抽取出共性定义在类中
-
对象就是根据类创建出来的实例,类似于根据模板生产物品
-
类由属性与方法组成
例如: Computer类 ------》电脑对象
类的组成
-
属性: 有什么 成员变量\实例变量
位置: 类的内部,方法的外部
语法:
- 声明属性: 数据类型 属性名; 例如:String name;
- 声明并初始化: 数据类型 属性名 = 值; 例如: int age = 18;
错误语法: 先声明,再赋值
例如: double score;
score = 100;//错误语法!!
class Student{
String name;
int age = 18;
double score;
//score = 100;错误
}
属性具有默认值:即属性的数据类型的默认值!
属性的作用范围:至少为整个类的内部
注意:当属性与局部变量命名冲突,局部变量优先!
补充:局部变量与属性的区别
局部变量 属性 位置 定义在函数(方法)内部 类的内部,方法的外部 默认值 没有默认值 具有默认值 作用范围 从定义的那一行开始,到定义所在代码块的结束 至少整个类的内部 命名冲突 作用范围重合内,不允许命名重复 当属性与局部变量命名冲突,局部变量优先 -
方法: 干什么 成员方法 对象的具体的行为:吃喝拉撒睡、工作、学习、玩耍、等等
位置: 类的内部,其他方法的外部
语法:
修饰符 返回值类型 方法名(形参列表){
//方法实现
}
注意:函数是特殊的方法!函数声明中需要写上static修饰符;而方法一般不写static
class Student{
String name = “小郭”;
int age = 18;
double score;
//score = 100;错误public void study(){
//局部变量优先!
//String name = “小红”;
System.out.println(name+“沉迷学习无法自拔”);
}
public void eat(){
System.out.println(“吃饭饭”);
}
public void sleep(){
System.out.println(“睡觉觉”);
}
} -
构造方法: Java规定的具有特殊功能的方法
作用: 可以用来配合new关键字创建对象,并且可以在创建对象的过程中选择是否为对象属性赋值!
分类:
-
无参构造方法 没有形参列表,在创建对象时无法为对象属性赋值;可以在对象创建成功后,通过其他方式赋值
语法: public 类名(){}
-
有参构造方法 具有形参列表,在创建对象时可以将形参的值赋值给属性
语法: public 类名(形参列表){ //赋值语句 }
注意:
-
-
构造方法的方法名必须和类名相同!
-
构造方法没有返回值类型,注意连void都没有
-
构造方法无法手动调用,只有在创建对象时被调用一次
-
若代码中没有定义任何构造方法,默认提供一个公开无参构造方法
经验:
-
一般的,若类中具有属性,需要提供有参、无参构造方法
-
可以定义多个形参个数不同的有参构造方法
//学生类
class Student{
//属性
String name = “小红”;
int age = 18;
double score;
//score = 100;错误
//普通的行为方法
public void study(){
//局部变量优先!
//String name = “小郭”;
System.out.println(name+“沉迷学习无法自拔”);
}
public void eat(){
System.out.println(“吃饭饭”);
}
public void sleep(){
System.out.println(“睡觉觉”);
}//无参构造方法
public Student(){}
//具有两个参数的有参构造方法
public Student(String n,double s){
name = n;
score = s;
}
//具有三个参数的有参构造方法
public Student(String n,int a,double s){
name = n;
age = a;
score = s;
}
}
思考:普通方法与构造方法的区别?
答: 普通方法是人为定义的一些具体功能、行为方法,例如吃喝拉撒睡、工作学习等等
而构造方法它的作用是Java实先规定好的,是用来创建对象的;它们的关系就好像主函数与普通函数的关系
java中常见类的使用
-
Math 常见数学函数
-
Arrays 操作数组的工具类,toString,sort方法
-
Random 随机数,种子的概念
-
String,Integer 查看内部状态,与相应的方法
-
ArrayList 可以代替数组
创建对象
创建对象的方式:
创建对象的过程称为实例化,对象的属性和方法称为实例(instance)成员
-
通过无参构造方法创建对象
语法: 类名 引用 = new 类名(); 例如:Student s1 = new Student();
-
通过有参构造方法创建对象
语法: 类名 引用 = new 类名(实参列表); 例如:Student s2 = new Student(“小郭”,20,80);
使用对象:
-
使用对象的属性:
-
通过 引用.属性名; 获取该对象的该属性
-
通过 引用.属性名 = 值; 完成对该对象的该属性的再次赋值
-
-
使用对象的方法:
- 通过 引用.方法名(实参列表) 调用该对象的该方法
class TestObject{
public static void main(String[] args){
//通过无参构造方法创建对象
Student s1 = new Student();
System.out.println(s1.name+" “+s1.age+” “+s1.score);
s1.study();
s1.score = 100;
System.out.println(s1.name+” “+s1.age+” "+s1.score);
//通过有参构造方法创建对象
Student s2 = new Student(“小郭”,20,80);
System.out.println(s2.name+" “+s2.age+” "+s2.score);
s2.study();
}
}
//学生类
class Student{
//属性
String name = “小红”;
int age = 18;
double score;
//score = 100;错误
//普通的行为方法
public void study(){
//局部变量优先!
//String name = “小郭”;
System.out.println(name+“沉迷学习无法自拔”);
}
public void eat(){
System.out.println(“吃饭饭”);
}
public void sleep(){
System.out.println(“睡觉觉”);
}
//无参构造方法
public Student(){}
//具有两个参数的有参构造方法
public Student(String n,double s){
name = n;
score = s;
}
//具有三个参数的有参构造方法
public Student(String n,int a,double s){
name = n;
age = a;
score = s;
}
}
重点:
程序中的对象与现实中的对象的的关系
类与对象的关系
类的组成,每个组成部分的作用及其语法、使用、注意事项
普通方法与构造方法的区别
无参构造方法与有参构造方法的区别,以及根据二者创建出来的对象的区别
创建对象的语法,对象的属性与方法的调用
明白int a = 10; 与 JavaKid jk = new JavaKid()的异同
基本数据类型变量与引用数据类型变量的异同
方法重载的语法及要求
this关键字
public Worker(String n,int a,double s){
name = n;
age = a;
salary = s;
}
存在问题: 不满足标识符命名规范,无法望名知意!
修改后:
public Worker(String name,int age,double salary){
name = name;
age = age;
salary = salary;
}
存在问题: 形参也属于局部变量,此时形参名与属性名重复,局部变量优先,即形参优先!那么此时 name = name中的两个name都是形参name,所以无法完成对属性赋值
需要使用this将局部变量形参与属性区别开!!!
this的用法:
-
用在构造方法或普通方法中,代表当前实例对象
-
this.属性名; 代表当前对象的属性
-
this.方法名(实参); 代表调用当前对象的方法
public Worker(String name,int age,double salary){
this.name = name;
this.age = age;
this.salary = salary;
}
public void method(){
int age = 20;
System.out.println(“局部变量:age”+age);
System.out.println(“属性:age”+this.age);
} -
-
必须要用在构造方法中,表示调用本类的其他构造方法
-
this(实参) 代表调用本类中具有相应形参的构造方法
-
注意: 该语句,必须写在构造方法中的第一行
public Student(String name,int age){
this.name = name;
this.age = age;
}
public Student(String name,int age,double score){
this(name,age);
this.score = score;
} -
class TestThis{
public static void main(String[] args){
Student s = new Student(“zhangs”,18,100);
s.study();
s.method();
}
}
//模板
class Student{
String name ;
int age;
double score;
public Student(){}
public Student(String name,int age){
this.name = name;
this.age = age;
}
public Student(String name,int age,double score){
this(name,age);
this.score = score;
}
public void study(){
System.out.println(name+"沉迷学习无法自拔");
}
public void method(){
int age = 20;
System.out.println("局部变量:age"+age);
System.out.println("属性:age"+this.age);
}
}
final关键字
final关键字修饰变量,则该变量值不能改变,对基本数据类型与引用变量均适用
final int i=1;final Circle c1 = new Circle();
什么时候使用final?
当希望获得一个常量,如Math.PI
final常与staic联合使用,作为类常量
或者希望某个引用类型变量只能指向一个指定对象
创建对象时必须初始化final属性
name属性在初次赋值后就不能改变,即不能指向其他String对象
final修饰类
- 该类不可被继承
- 一般用于创建不可变类(immutable)
final修饰方法
- 该方法是最终方法,不能被子类覆盖
- 保护该方法的代码不会被修改
- Object中的很多方法都使用final修饰
三大特性
封装
问题:目前,可以随意的调用、修改一个对象的属性,这种行为是不合理的!!!
概念:是一个边界,是一个屏障,可以保护对象内部的数据不被外界随意访问
实现封装:借助访问(权限)修饰符–private 私有的
| 访问修饰符 | 作用范围 |
|---|---|
| public 公共的、公开的 | 外界可以随意访问 |
| private 私有的 | 只能在本类中使用 |
-
属性封装
-
语法:private 数据类型 属性名;
-
注意:一般的,当将属性私有化后,需要提供公开的get\set方法,供外界使用,从而去获取及修改属性
即使用封装隐藏内部状态,所有的通信都通过对象的方法来实现
注意:
1. 每个私有属性都必须有自己独立的get(获取属性)\set(修改属性)方法 2. get\set命名规范:get\set+属性名(首字母大写) 3. 若属性的数据类型为boolean类型,get方法可以命名为:is+属性名(首字母大写);set方法不变 4. 可以根据需求,选择是否提供get\set方法class TestDog{
public static void main(String[] args){ Dog d = new Dog(); d.setName("旺财"); d.setAge(2); System.out.println(d.getName()+" "+d.getAge()); }}
class Dog{private String name; private int age; private boolean sex; public Dog(){} public Dog(String name,int age){ this.name = name; this.age = age; } public Dog(String name,int age,boolean sex){ this(name,age); this.sex = sex; } 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 boolean isSex(){ return sex; } public void setSex(boolean sex){ this.sex = sex; }}
-
思考:为什么将属性封装后,还提供get\set方法?
答: 封装只是起到保护的作用,而不是完全隔绝!
- 方法封装 将一些只用于本类,并不希望被外界调用的方法私有化,禁止外界调用!
重点:
this.与this(实参)的区别及使用注意事项
对象的创建过程,明白属性的三个赋值时机
明白引用中存储的内容,及对象的存储地方
基本数据类型变量与引用数据类型变量的区别:存储、传递
private与public的区别,作用范围
get\set方法的作用及语法及注意事项
继承
生活中的继承:一般的,指儿子继承爸爸的一些物品、财产
Java中的继承:指一个类(子类)可以继承(使用)另一个类(父类)的某些属性和方法
概念: 父类是子类共性的抽取!在父类中只能定义所有子类的共性部分;父类—子类是中“一般–特殊”的关系
语法:class 子类类名 extends 父类类名{}
继承的特点:当继承关系建立后,子类可以直接使用父类中可以被子类继承的方法与属性;子类中也可以定义自己独有的属性与方法;子类继承父类的所有非私有成员(不包含构造器)
继承的好处:减少代码冗余,提高代码的可复用性
注意:
-
一般的,只有满足 is a的关系,才能建立继承关系
-
构造方法不能被继承
-
Java是单继承—一个子类只能有一个直接父类!但是可以多级继承,可以被继承的属性或方法也是叠加的
补充: 访问修饰符
访问修饰符 本类 同包 其他包子类 不同包不子类 继承性 public公开的 √ √ √ √ 可以被继承 protected受保护的 √ √ √ 可以被继承 default默认的 √ √ 同包子类可继承 private私有的 √ 不能被继承 从宽到严: public -> protected -> default -> private
注意:
以上四个访问修饰符都可以修饰 属性、方法、构造方法
只有个public与default可以修饰类
以上四个均不可以修饰局部变量
package d10;
public class ClassA{
//公开的
public int a = 10;
//受保护的
protected int b = 20;
//默认的
int c = 30;
//私有的
private int d = 40;}
package d10;
//同包子类
public class ClassB extends ClassA{
public ClassB(int a,int b,int c,int d){
this.a = a;
this.b = b;
this.c = c;
this.d = d;//无法继承
}}
package p10;
import d10.ClassA;
//不同包子类
public class ClassC extends ClassA{
public ClassC(int a,int b,int c,int d){
this.a = a;
this.b = b;
this.c = c;//无法继承
this.d = d;//无法继承
}}
package p10;
import d10.ClassA;
//不同包不子类
public class ClassD{
public static void main(String[] args){
ClassA ca = new ClassA();
System.out.println(ca.a);
System.out.println(ca.b);//无法访问
System.out.println(ca.c);//无法访问
System.out.println(ca.d);//无法访问
}
}
class TestAnimal{
public static void main(String[] args){
Dog d = new Dog(“旺财”,2,“红色”);
d.eat();
d.sleep();
d.lookDoor();
System.out.println(d.name+" “+d.age+” "+d.color);
}
}
//父类 只能定义所有子类的共性
class Animal{
String name;
int age;
public void eat(){
System.out.println("吃饭饭");
}
public void sleep(){
System.out.println("睡觉觉");
}
public Animal(){}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
}
//子类
class Dog extends Animal{
String color;
public void lookDoor(){
System.out.println("看门门");
}
public Dog(){}
public Dog(String name,int age,String color){
this.name = name;
this.age = age;
this.color = color;
}
}
//子类
class Bird extends Animal{
String pinZhong;
public void fly(){
System.out.println("飞高高");
}
public Bird(){}
public Bird(String name,int age,String pinZhong){
this.name = name;
this.age = age;
this.pinZhong = pinZhong;
}
}
//子类
class Fish extends Animal{
double size;
public void swim(){
System.out.println("划水水");
}
public Fish(){}
public Fish(String name,int age,double size){
this.name = name;
this.age = age;
this.size = size;
}
}
方法覆盖
概念:OverRide,又称为方法重写,即在子类中可以将从父类继承到的方法进行重新实现
语法要求:
-
方法三要素(返回值类型、方法名、形参列表)必须完全相同
-
访问修饰符相同或更宽
注意:
-
子类中覆盖后的方法优先执行
-
若父类中有一个方法使用private修饰,此时子类中有一个方法三要素完全与之相同、但访问修饰符为public的方法,此时不构成方法覆盖,因为子类继承不到该方法
-
@Override注解
告诉编译器这里覆盖了父类的方法,如果在父类中未找到相应方法,会报错
class TestAnimal{
public static void main(String[] args){
Dog d = new Dog(“旺财”,2,“红色”);
d.eat();
d.sleep();
d.lookDoor();
System.out.println(d.name+" “+d.age+” "+d.color);
}
}
//父类 只能定义所有子类的共性
class Animal{
String name;
int age;
public void eat(){
System.out.println("吃饭饭");
}
public void sleep(){
System.out.println("睡觉觉");
}
public Animal(){}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
}
//子类
class Dog extends Animal{
String color;
public void eat(){
System.out.println("狗吃骨头");
}
public void lookDoor(){
System.out.println("看门门");
}
public Dog(){}
public Dog(String name,int age,String color){
this.name = name;
this.age = age;
this.color = color;
}
}
对象的创建过程
-
无父类的创建过程
-
分配空间,为属性赋默认值
-
属性初始化,为属性赋初始值
-
执行构造方法,完成对象的创建,为属性赋构造参数值
-
-
有父类的创建过程
-
分配空间(父类+子类),为父子类属性赋默认值
-
初始化父类属性,为父类属性赋初始值
-
执行父类构造方法,完成父类对象的创建,为父类属性赋构造参数值
-
初始化子类属性,为子类属性赋初始值
-
执行子类构造方法,完成子类对象的创建,为子类属性赋构造参数值
-
-
总结:
-
创建子类对象时,必须先创建父类对象
-
子类对象由父类对象加上子类独有内容共同组成
-
class TestAnimal{
public static void main(String[] args){
Animal a = new Animal(“动物”,1);
System.out.println(a.getName());
Dog d1 = new Dog("狗1",2,"黑色");
// d1.setName("狗1");
System.out.println(d1.getName());//狗1
Dog d2 = new Dog();
System.out.println(d2.getName());//null
}
}
super关键字
当子类中定义了与父类中同名的属性时(属性遮蔽)或发生了方法覆盖时,需要加以区分,才能专项访问
子类中的属性名与父类中的属性名相同,这父类中的属性被屏蔽(隐藏)
只是被隐藏但还存在,可使用super关键字访问
super的两种用法:
-
用在构造方法、普通方法中,代表父类对象
-
super.属性名; 获取父类属性
-
super.方法名(); 调用父类方法
注意:该用法中的属性与方法必须是子类可以继承到的
//子类
class Dog extends Animal{
String color;public void eat(){
System.out.println("狗吃骨头");}
public void lookDoor(){System.out.println("看门门");}
public Dog(){}
public Dog(String name,int age,String color){super.name = name; super.age = age; this.color = color;}
-
}
class TestMyClass{
public static void main(String[] args){
MyClassB mb = new MyClassB();
mb.method();
mb.print();
}
}
class MyClassA{
int value = 10;
public void print(){
System.out.println(value);
}
}
class MyClassB extends MyClassA{
int value = 20;
public void print(){
//调用父类中被覆盖的print方法
super.print();
System.out.println(value);
}
public void method(){
int value = 30;
System.out.println("局部变量:"+value);//30
System.out.println("子类属性:"+this.value);//20
System.out.println("父类属性:"+super.value);//10
}
}
-
必须用在子类构造方法中, 用来制定创建父类对象时,使用父类的哪个构造方法
-
super(); 调用父类无参构造方法
-
super(实参); 调用父类有参构造方法
注意:
-
-
super(…)必须写在子类构造方法中的第一行
-
this(…)与super(…)不能同时出现
-
若子类构造方法第一行不是this(…)也不是super(…),则默认为super();
class Dog extends Animal{
String color;public void eat(){
System.out.println("狗吃骨头");}
public void lookDoor(){System.out.println("看门门");}
public Dog(){}
public Dog(String name,int age,String color){super(name,age); this.color = color;}
}
面向对象代码规范写法:
//父类
class Animal{
//父类私有属性
private String name;
private int age;
//get、set方法
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 Animal(){}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
//普通方法
public void eat(){
System.out.println(“吃饭饭”);
}
public void sleep(){
System.out.println(“睡觉觉”);
}
}
//子类继承父类
class Dog extends Animal{
//子类独有私有化属性
private String color;
//子类get\set方法
public String getColor(){
return color;
}
public void setColor(String color){
this.color = color;
}
//子类有参无参构造方法
public Dog(){}
public Dog(String name,int age,String color){
//调用父类有参构造方法创建父类对象,完成父类name与age属性的赋值
super(name,age);
this.color = color;
}
//子类覆盖父类中的eat方法
public void eat(){
System.out.println(“狗吃骨头”);
}
//子类独有方法
public void lookDoor(){
System.out.println(“看门门”);
}
}
多态
一个动物------> 狗
一个动物------> 猫
Dog d = new Dog(); 狗 是狗
Animal a = new Dog(); 狗 是动物
概念:父类的引用可以指向子类的对象
语法:父类类名 引用 = new 子类类名(实参);
特点:
-
父类的引用指向子类对象,并不会改变对象的实际类型
-
当使用多态时,只能调用引用类型中具有的方法
-
当使用多态时,会优先执行子类中覆盖后的方法
总结:方法调用看引用类型;方法的执行结果看对象的实际类型(子类类型)
多态性:相同形态,不同行为,使程序在运行中具备动态选择代码执行的能力
注意:方法具有多态,属性没有多态!调用属性的引用是什么类型,就会获取什么类型中的属性。
class TestAnimal{
public static void main(String[] args){
Animal a = new Animal(“a”);
a.eat();//吃饭饭
a.sleep();//睡觉觉
System.out.println(a.name);//a
Dog d = new Dog("d");
d.eat();//狗吃骨头
d.sleep();//睡觉觉
d.lookDoor();//看门门
System.out.println(d.name);//null
Animal d1 = d;
System.out.println(d1.name);//d
Animal dog = new Dog("dog");
dog.eat();//狗吃骨头
dog.sleep();//睡觉觉
//错误,只能调用引用类型中具有的方法
//dog.lookDoor();
System.out.println(dog.name);//dog
}
}
class Animal{
String name;
public Animal(){}
public Animal(String name){
this.name = name;
}
public void eat(){
System.out.println("吃饭饭");
}
public void sleep(){
System.out.println("睡觉觉");
}
}
class Dog extends Animal{
//注意:一般情况下,子类中不会定义与父类中同名的属性
//String name;
public Dog(){}
public Dog(String name){
super(name);
}
public void eat(){
System.out.println("狗吃骨头");
}
public void lookDoor(){
System.out.println("看门门");
}
}
引用类型的类型转换
-
子类类型引用可以直接赋值给父类类型引用
Dog d = new Dog();
Animal a = d; -
在多态场景下,父类类型引用赋值给子类类型引用,需要强转
Animal a = new Dog();
Dog d = (Dog)a;//强转的目的:编译器在编译代码时,无法准确得知引用a指向的对象的实际类型,而将Animal类型转为Dog类型,可能会出错,所以需要强转,告诉编译器,允许转换
Animal a = new Cat();
Dog d = (Dog)a;//由于强转,导致编译通过;但是解释器在工作的时候,会确认a指向的对象的实际类型,由于a指向的Cat类型对象,此时强转为Dog类型,所以会运行报错!!–java.lang.ClassCastException类型转换异常
Animal a = new Animal();
Dog d = (Dog)a;//编译通过,运行报错,原因同上!!
Cat c = new Cat();
Dog d3 = (Dog)c;//编译报错,不兼容类型!因为Cat不可能转换为Dog! -
没有继承关系的两种类型,不允许相互转换
Person p = new Person();
Dog d = (Dog)p;//编译报错,不兼容类型!因为Person不可能转换为Dog!
instanceof关键字
语法: 引用 instanceof 类名 注意:这是一个boolean表达式,结果要么为true,要么为false
作用:判断引用指向的对象的实际类型与关键字后面的类名类型是否兼容,若兼容,则返回true,表示可以强转;若不兼容,则返回false,表示不能强转;
例如:
if(a instanceof Dog){
Dog d = (Dog)a;
}else{
Cat c = (Cat)a;
}
====================================================================================
class TestInstanceof{
public static void main(String[] args){
//多态的应用场景1:定义父类类型的数组,可以存储子类类型的对象
int[] arr = {1,2,3,4,5};
Animal[] as = new Animal[4];
as[0] = new Dog();
as[1] = new Cat();
as[2] = new Dog();
as[3] = new Cat();
//需求:调用数组as中所有Dog对象的lookDoor方法,Cat对象的catchMouse方法
for(int i=0;i<as.length;i++){
if(as[i] instanceof Dog){
Dog d = (Dog)as[i];
d.lookDoor();
}else{
Cat c = (Cat)as[i];
c.catchMouse();
}
}
}
}
多态的应用场景
-
应用在数组上,定义父类类型数组,可以存储子类类型对象;
Animal[] as = {
new Animal(),
new Dog(),
new Cat()
} -
应用在方法形参上,方法形参定义为父类类型,调用方法时,传入实参的类型可以为父类对象或其子类对象
-
应用在返回值类型上,方法返回值类型定义为父类类型,方法执行结束时,可以返回父类对象或其子类对象
class Test{
public static void main(String[] args){Dog d = new Dog(); Cat c = new Cat(); Wolf w = new Wolf(); Tiger t = new Tiger(); feed(d); feed(c); Animal a = sell(2000000); System.out.println(a);}
//避免了方法重载,提高了代码的可重用性
public static void feed(Animal a){a.eat();}
public static Animal sell(double money){if(money>1000000){ return new Tiger(); }else if(money>10000){ return new Wolf(); }else{ return new Dog(); }}
/*
public static void feed(Dog d){d.eat();}
public static void feed(Cat c){c.eat();} */
}
class Animal{
public void eat(){System.out.println("吃饭饭");}
}
class Dog extends Animal{
public void eat(){System.out.println("狗吃骨头");}
}
class Cat extends Animal{
public void eat(){System.out.println("猫吃鱼");}
}
class Wolf extends Animal{
public void eat(){System.out.println("狼吃喜洋洋");}
}
class Tiger extends Animal{
public void eat(){System.out.println("老虎吃人");}
}
多态的好处
-
减少代码冗余,提高代码的可重用性
-
解耦合(依赖倒转原则)
重点:
多态的概念及语法,三个特点
理解:方法具有多态,属性没有多态
instanceof的真正用法,及其判断的内容
多态的三个应用场景
抽象类
使用abstract修饰的类为抽象类
-
抽象类不能实例化,只能作为其他类的父类
-
生来就应该被继承
public abstract class Shape{}
使用abstract修饰的方法为抽象方法
-
只有声明,没有实现方法
public abstract double get();
2.意味着该方法需要到子类才能确定其实现
子类继承抽象类,一般要实现父类的抽象方法
- 体现子类的特有实现
子类如果只实现部分抽象方法,依然是抽象类
- 一个类中只要有抽象方法,必然是抽象类
- 此类必须声明为abstract
- 一个抽象类中可以有非抽象方法
本文介绍了面向对象编程的基本概念,包括面向对象的编程思想、类与对象的关系、类的组成、构造方法、封装、继承和多态。通过实例详细阐述了如何在Java中创建和使用对象,以及this和super关键字的用途。此外,还讨论了Java中的final关键字和访问修饰符,以及方法覆盖和多态的实现。

2406

被折叠的 条评论
为什么被折叠?



