概念
面向对象:oop (Object Oriented Programming)
是一种编程思想(写代码的固定套路/步骤)
面向对象:c# python object-c java scala
面向过程:pop (Procedure Oriented Programming)
面向过程:c c++
解决吃饭:
1 自己做饭:
洗菜–洗米–煮米–炒菜–盛饭–吃饭–刷碗
面向过程:亲力亲为
按动作把解决问题的过程分成多个步骤 逐个步骤去完成 最终解决问题
2 让别人帮你做
找饭店—点菜(指挥厨师做饭)—吃饭
面向对象:找正确的对象(万物皆对象)
找具有帮助我解决问题功能的对象 指挥对象解决问题
面向对象优点:
1 由执行者转换为指挥者 简化过程
2 提高代码复用性
3 更符合现在人的生活–(怎么生活 就怎么写代码)
面向对象的步骤
需求:让大象进行自我介绍
给电脑描述人这种数据的类型-------->电脑中创建一个人的模型----->模型的数据和大象保存一致----->电脑中有个大象的模型----->大象电脑中进行自我介绍
public class Demo01Oop {
/*
需求:让大象进行自我介绍
给电脑描述人这种数据的类型-------->
电脑中创建一个人的模型----->
模型的数据和真实大象保存一致----->
电脑中有个大象的模型----->
大象电脑中进行自我介绍
分析过程用代码实现
1 给电脑描述人的类型
数据+功能
用变量表示数据
用方法表示功能
创建一个类 描述人这个类型:通过变量表示数据 通过方法表示功能
2 根据描述 在电脑中创建一个 人类的模型
格式:类名 对象名=new 类名();
3
*/
public static void main(String[] args) {
//2 根据描述 在电脑中创建一个 人类的模型
Person p1=new Person();
//3 给对象的变量赋值(与现实实物的数据保持一致)
p1.sex='男';
p1.age=66;
p1.name="大象";
p1.job="喝水";
//4 调用对象的方法 来解决问题
p1.show();
}
}
//创建一个类 描述人这个类型
class Person{
//通过变量表示数据
char sex;
int age;
String name;//String是字符串类型
String job;
//通过方法表示功能
void show() {
System.out.println("我加"+name+",今年"+age+"岁,我是"+sex+"生,职位是:"+job);
}
void smoke() {
System.out.println(name+"正在吸烟!");
}
}
类和对象的概念
**成员:类中定义的变量和方法
成员变量:类中定义的变量
成员方法:类中定义的方法
类中定义什么成员变量 此类创建的对象就拥有什么属性
类中定义什么成员方法 此类创建的对象就拥有什么功能
类: 对一类事物的描述
是成员变量和成员方法的封装
是用于创建对象的模板/图纸
对象:多个基本数据有机组合形成一个复杂数据
对象是根据类创建的实例
现实实物在电脑中的模型 **
public class Demo02Oop {
//面向对象的方法 不用再加修饰符
public static void main(String[] args) {
//2 根据类创建对象
Student s1=new Student();
//Student类中定义了什么变量 此类创建的对象就有什么数据
//Student类中定义了什么方法 此类创建的对象就有什么功能
//3 给对象的变量赋值
s1.age=19;
s1.name="梁贵莹";
s1.sex='男';
s1.sid=1001;
//4 调用对象的方法
s1.show();
s1.printHe(12, 13);
Student s2;//定义一个引用 此引用要指向一个Student类型的对象
s2=new Student();//一个new 就新创建一个对象
s1=s2;//让s1指向s2指向的对象(21行的对象) s1和第八行的对象无关了
//对象的变量不赋值 有默认初始值:0/null
s2.show();//学生:name=null,age=0,sid=0,sex=' '
s2.sex='女';
s2.show();
//每个对象都拥有一套类中定义的变量和方法
System.out.println(s1);//com.zhiyou100.day07.Student@7852e922
}
}
//1 创建类描述学生这个类型
// 类中需要定义那些变量和方法 取决于需求
class Student{
//通过变量表示数据
int sid;
String name;
char sex='男';//给此类创建的所有对象的sex属性赋默认值
int age;
//通过方法表示功能
void show() {
System.out.println("学生:name="+name+",age="+age+",sid="+sid+",sex="+sex);
}
//方法中可以使用两种变量:类中直接定义的变量+参数列表
//把什么样的变量 在类中定义
//把什么样的变量 在方法的参数列表中定义
void printHe(int a,int b) {
System.out.println(name+"正在算术:"+a+"+"+b+"="+(a+b));
}
}
方法重载
public class Demo03Overload {
//重载:overload
//同一个类中 几个方法 方法名相同 参数列表不同的现象
//重载要求:必须是同一个类
// 方法名必须相同
// 参数列表必须不同:参数个数不同 参数类型不同 参数顺序不同
//方法重载:类似于生活中的同卵双胞胎
//为什么几个方法要重载:这几个方法功能基本一致 只是需要的参数不同而已
public static void main(String[] args) {
//创建对象
Stu s=new Stu();
s.name="梁贵莹";
s.add(1, 2);
s.add(1, 1.2);//重载方法调用 通过参数列表区分
s.show();//普通方法调用 通过名字区分
}
}
//一个源文件中可以有多个class
//只能有一个public修饰的class 并且此class的名字必须和源文件名字一致
class Stu{
String name;
//求和:两个int
void add(int a,int b) {
System.out.println(name+"正在求和:两个int "+a+"+"+b+"="+(a+b));
}
//求和:一个int 一个double
void add(int a,double b) {
System.out.println(name+"正在求和:1个int 1个double "+a+"+"+b+"="+(a+b));
}
void add(int a,int b,int c) {
System.out.println(name+"正在求和:三个int "+a+"+"+b+"+"+c+"="+(a+b+c));
}
void add(double a,int b) {
System.out.println(name+"正在求和:1个double 1个int "+a+"+"+b+"="+(a+b));
}
void show() {}
}
构造方法
public class Demo04Constructor {
/*构造方法:构造器 构造函数 Constructor
*构造方法:类中定义的用于构建创造对象的方法
*构造方法特点:
* 1 构造方法没有返回值 不用void标示
* 2 构造方法名字必须和类名相同
* 3 对象不能调用构造方法
* 4 构造方法只能被关键字new调用 每调用一次 创建一个新的对象
* 5 一个类如果没有构造方法 默认有一个无参数的构造方法
* 6 构造方法的参数列表一般是给对象的属性赋值
* */
public static void main(String[] args) {
//创建对象
Teacher t=new Teacher();
t.age=31;
t.show();
Teacher t1=new Teacher();
}
}
class Teacher{
int age;
String name;
String subject;
float salary;
void show() {
System.out.println("Teacher:name="+name+",age="+age+".subject="+subject+",salary="+salary);
}
// //Teacher类中没有Teacher() 但可以使用 说明编译器默认添加一个
// void Teacher() {//普通方法
// //This method has a constructor name
// System.out.println("void Teacher()");
// }
Teacher(int a,String n) {//构造方法
age=a;name=n;//构造方法的参数列表一般是 给对象的属性赋值
System.out.println("Teacher(int a,String n) ");
}
Teacher() { }
}
this使用
/*this: 当前对象:::哪个对象调用当前方法 this指的就是哪个对象
* 使用场景1:成员变量与局部变量重名时 变量名指向的是局部变量
* 通过this.变量名来调用成员变量
* 注意:方法中调用成员 前面默认有this.
* 使用场景2: 构造方法相互调用通过this(参数列表)
* 注意:this(参数列表) 必须是第一个语句
* */
class Demo{
int a=2;
int b;
int c;
int e;
Demo(){}
//为什么写多个构造方法:满足创建不同对象的需求
Demo(int a,int b,int c){
this.a=a;this.b=b;this.c=c;
System.out.println("Demo(int a,int b,int c)");
}
Demo(int a,int b,int c,int e){
this(a,b,c);//调用构造方法Demo(int a,int b,int c) 复用其方法体
this.e=e;
System.out.println("Demo(int a,int b,int c,int e)");
}
void show() {
System.out.println("a="+a+",b="+b);
}
//局部变量:方法参数列表以及方法体中定义的变量
//成员变量:类中定义的变量
void hai(int a) {
int c=2;
//此方法中可以访问到两个a:成员变量a和方法参数a
//成员变量与局部变量重名
System.out.println("a="+a);//变量名默认指向的局部变量----就近原则
System.out.println("this.a="+this.a);//通过this.变量来调用成员变量
System.out.println("this="+this);
System.out.println(b);//方法中调用成员 前面默认有this. //this.b
show();//this.show();
}
}
构造方法和普通方法区别
//4 总结构造方法和普通方法的区别
//构造方法:类中用于构建创建对象的方法
//普通方法:类中定义的具有指定功能的代码块
//相同之处:都是方法-都是类的成员
//不同之处1:格式不同
// 普通方法必须有返回值类型的标示 没有返回值用void标示
// 构造方法没有返回值 不用void标示
//不同之处2:调用不同
// 普通方法被对象调用 一个对象可以调用多次
// 构造方法不能被对象调用 只能被关键字new调用 每调用一次创建一个对象
//不同之处3:是否有默认
// 一个类如果没有定义构造方法 默认有一个无参数的构造方法
//不同之处4:命名不同
// 构造方法名字必须是类名 普通方法名字可以是类名(但不规范)
//不同之处5:作用不同
// 构造方法作用:创建对象
// 普通方法作用:代表的是本类创建的对象具有的某个指定功能
setValue
给对象赋值的方式
/*需要一个红色的车:
* 1 出厂就是红色的
* 2 买回来后自己喷漆
* 3 买回来后 去4s店喷漆
* 4 出厂定制
*给对象的属性赋值方式
*方式1:对象名.属性名
* eg:c.color='红';
* 特点:必须先创建对象 只能给当前对象的属性赋值
* 缺点:不安全 不可控 Car类无法控制color属性的合理取值
*方式2: 通过构造方法参数列表给属性赋值
* eg:Car cc=new Car("bmw");
* 特点:对象一创建 属性就有指定的值 只能给当前对象的属性赋值
* 数据可控
*方式3: 在类中直接给成员变量赋值
* eg:double money=19999;
* 特点:此类创建的所有对象的此属性的初始值都是此值
*
*方式4:通过普通方法的参数列表给属性赋值
* eg: cc.setNumber("豫A 88888");
* 特点:必须先创建对象 只能给当前对象的属性赋值
* 首选
*/
创建对象内存图
Private 属性私有化封装
/*封装:对实现细节进行包装隐藏
* 类---对描述同一类事物的数据和功能的封装
* 属性私有化: 让属性对可信任的类/对象可见 对不可信任的类/对象隐藏
* 目的:数据可控
*
*1 属性添加修饰符private (只有在本类中可以访问)
*2 提供公共的getter/setter方法 来间接访问
* public 类型 getXxx();
* public void setXxx(类型 xxx);
*3 不可信任的对象 通过调用方法来操作属性
*
*注意:所有的属性必须私有化
* */
public static void main(String[] args) {
Demo02 d1=new Demo02();
d1.sex='1';
//d1.age=19;//无法直接访问
d1.setAge(-19);
d1.show();
}
}
class Demo02{
private int age;
char sex;
public static void main(String[] args) {
Demo02 d1=new Demo02();
d1.sex='1';
d1.age=19;//本类为可信任的类 可以直接访问
}
public int getAge() {return this.age;}
public void setAge(int age) {
if(age<=0||age>=130) {return;}
this.age=age;
}
void show() {
System.out.println("age="+age+",sex="+sex);
}
}
Static 静态
/*
* 案例Stu1:每个学生都有自己的name和sex
* 每个学生也都拥有属于自己的班级名称 公司名称 饮水机----和现实不一致---现实中这些数据只有一份 大家共同使用
*
* static:静态的 修饰符:可以(修饰内部类+静态代码块+)成员变量+普通方法
* static修饰成员变量:
* 1 static修饰的变量 不但可以被对象调用 还可以通过类名直接调用
* 2 static修饰的变量是共享数据 所有对象共用一个
* static修饰普通方法
* 1 static修饰的方法 不但可以被对象调用 还可以通过类名直接调用
* 2 静态方法只能调用静态成员(静态成员变量+静态普通方法)
* 非静态方法可以调用所有的成员(静态成员+非静态成员)
*
* 什么情况下把一个成员变量定义为静态变量
* :当数据不是仅属于某个对象 而是所有对象公用时 定义为静态变量
* 什么情况下把一个普通方法定义为静态方法
* :当一个方法中不涉及非静态成员时 尽量把此方法定义为静态方法
*
* 静态成员(静态成员变量+静态普通方法) 在静态区域中加载
* 当类加载 会为此划分一块区域作为静态区域 来加载本类所有静态成员
*
* 类成员---被static修饰的成员--static修饰的成员变量和成员方法
* 实例成员--没有被static修饰的成员
* 类变量--被static修饰的成员变量
* 类方法--被static修饰的成员方法
* 实例变量--没有被static修饰的成员变量
* 实例方法--没有被static修饰的成员方法
*
* */
static内存图
Extends 继承
/*
继承: 龙生龙 凤生凤
关键字:extends
概念: 当定义一个新类时 如果新类拥有一个现有的类所有成员
可以让此新类从现有的类派生、衍生
新类:子类
现有的类:父类、超类、根类
格式: class 子类 extends 父类{}
作用: 实现类的复用+创建类与类之间的关系
特点: 1 子类会继承父类中定义的所有实例成员
2 子类继承了父类的私有成员 但不能直接使用
3 子类不能继承父类的构造方法
4 子类中可以定义父类没有的成员--子类特有
5 子类可以根据自己的需求对继承于父类的成员进行重新定义
重新定义父类的成员变量要求:变量名相同即可
重写定义父类的普通方法要求:
方法声明必须和父类一致:方法名相同 参数列表相同 返回类型相同
6 java只支持类与类的单继承:一个子类只能有一个直接父类
7 所有的类直接或者间接继承Object::::
一个类如果没有继承其他类 默认继承Obejct类
* */
public static void main(String[] args) {
Teacher t1=new Teacher();
t1.show();
System.out.println("t1.name="+t1.name);
}
}
class Person{
private int age;
String name="父类name";
void show() {System.out.println(name+":"+age);}
Person(){}
Person(int a){}
}
//Teacher中拥有Person类中的所有成员
class Teacher extends Person{
// int age;
// String name;
// void show() {System.out.println(name+":"+age);}
//String name="子类name";//重新定义成员变量
int name=1;//重新定义成员变量
void show(int a) {}//子类特有
void show() {//重新定义普通方法---重写 override
System.out.println(name+":"+salary);
}
float salary;//子类特有
void hai() { }
}
继承内存图
重载(Overload)和重写(Override)的区别
概念: 重载--overload--同一个类中几个方法 方法名相同参数列表不同的现象
重写--override--子类根据自己的需求对父类的方法进行重新定义
相同之处:说的都是方法
要求方法名相同
不同之处:
1 涉及的类个数不同:
重载只涉及一个类
重写必须继承 涉及子类和父类
2 要求不同:
重载要求:方法名相同参数列表不同
重写要求:除了范围修饰符可以扩大 其他方法声明必须和父类完全相同
3 影响不同:
重载的方法之间互相没有影响:只是调用时不同通过方法名区分 而是通过参数列表区分
重写:子类重写父类的方法 子类中从父类继承的方法被隐藏
4 意义不同:
重载:几个方法基本功能相同 只是方法运行需要的原始数据不同而已
重写:子类根据自己的需求 对父类已有的功能进行扩展
范围修饰符
//范围修饰符:让被修饰者具有一些本来不具有的特征
// 用来指定被修饰者的作用范围
//public protected (default) private
//可以修饰:类、成员变量、方法
/* 关键字 名称 作用范围
* public 公共的 整个项目
* protected 受保护的 本包+其他包的子类
* (default) 省略的 本包
* private 私有的 本类
* */
注意:类只能加public和省略两种情况
super
/*
*super: 和 this比较起来学习
*this:当前对象/我自己的
*使用场景1:成员变量和局部变量重名 通过this.变量名来指向成员变量
* 注意:方法体中提到实例成员(成员变量+成员方法) 前面默认有this.
*使用场景2: 构造方法之间相互调用 通过this(参数列表)
* 注意:this(参数列表) 必须是第一个语句
*
*super: 父类 /我爹的
*使用场景1: 子类重新定义父类已有的成员 子类中从父类继承的成员会被隐藏
* 在子类方法中 通过super.成员 调用父类因被重新定义而隐藏的成员
* 注意:子类方法中 所有的子类成员前面默认有super.
*使用场景2: 所有的子类构造方法中第一个语句必须是super(参数列表) 来调用父类的构造方法
* (在创建子类对象时 通过super(参数列表)来调用父类的构造方法 把父类中定义的实例成员加载进子类对象内存中)
* 注意:所有子类构造方法中第一个语句默认是super()
* */
final
public class Demo07Final {
/*
* final :修饰符 最终的
* 可以修饰:类+成员方法+成员变量+局部变量
*
* final修饰类(最终类): 不能被继承
*
* final修饰的方法(最终方法): 不能被子类重写
*
* final修饰的变量(常量):值不能更改
* 1:final修饰的成员变量没有默认初始值
* 2:final修饰的变量不能二次赋值
*
* 把变量定义为final优点:
* 1 简化书写
* 2 增加可读性
*
* 注意:final常量命名规范:所有字母大写 单词之间用_分割
* final String MY_PERSON_ID="410185198600000000";
* */
public static void main(String[] args) {
DemoFinal d=new DemoFinal();
Demo071 d1=new Demo071(1);
d1.hai();
System.out.println(d1.b2);
//d1.b2=1;//The final field Demo071.b2 cannot be assigned
System.out.println(3.1415926);
final double pi=3.1415926;
System.out.println(pi);
System.out.println(pi);
final int a=1;//final类型的基本数据类型数据:不能二次赋值
final Demo77 d7=new Demo77();//final修饰的引用数据类型数据:不能再指向其他对象
d7.a=11;
}
}
class Demo77{
int a;
}
class Demo071{
int a;
//final修饰的成员变量没有默认初始值 必须显式赋值
//final int b;//The blank final field b may not have been initialized
//给final成员变量赋值方式1:
final int b1=1;//所有对象的b1值都是1
final int b2;
//给final成员变量赋值方式2:
Demo071(int b2){
this.b2=b2;
}
final void hai() {
System.out.println(b2);
}
}
class Demo071Zi extends Demo071{
//Cannot override the final method from Demo071
//void hai() {}
Demo071Zi(){super(1);}
}
final class DemoFinal{}
//class DemoFinalZi extends DemoFinal{}
//The type DemoFinalZi cannot subclass the final class DemoFinal
非静态final变量的赋值方式
1、定义初始值
final int a=10;
2、非静态代码块
final int b;
{
b=10;
}
3、调用构造方法初始化
final int c;
C(int c){
this.c=c;
}
静态final变量的赋值方式
为什么不能用构造方法初始化变量的值?
答:因为静态变量是随着类加载而加载的,构造方法是对象被创建时才被调用的方法,创建对象在类加载之后,所以构造方法不能对静态变量进行初始化。
1、定义初始化
static final int d=10;
2、静态代码块
final static int e;
static {
e=10;
}
成员变量和局部变量的区别:
- 1、从语法形式上看,成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;
成员变量可以被public,private,static等修饰符所修饰,而局部变量不能被访问控制修饰符及static所修饰;
但是,成员变量和局部变量都能被fianl所修饰。
2、从变量内存中地存储方式看,成员变量是对象的一部分,而对象存在于堆内存中,局部变量存在于栈内存。
3.从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失*。
4、成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外:被final修饰的但没有被static修饰的成员变量必须显示地赋值);而局部变量则不会自动赋值
抽象
public class Demo01Abstract {
/*抽象:abstract
*概念:笼统 模糊 不具体
* 修饰符:只能修饰类和方法
*特点:
* 1 抽象方法不能有方法体
* 2 有抽象方法的类必须是抽象类 但抽象类可以没有抽象方法
* 3 抽象类不能创建对象 但可以定义引用
* 4 抽象类有构造方法:抽象类的构造方法不是用于创建本类对象 而是用于帮助创建子类对象
* (在创建子类对象时 把抽象类中的非抽象方法和成员变量加载进子类对象内存中)
* 5 抽象类的子类除非重写所有的抽象方法(重写抽象方法---实现) 否则任然是抽象类
*作用:为子类定义规范
*思考:什么情况下把一个方法定义为抽象方法:::当信息不完整 方法体无法实现时
* 什么情况下把一个类定义为抽象类:::类没有必要创建对象时
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo01 d;
//d=new Demo01();//Cannot instantiate the type Demo01 抽象类不能创建对象
}
}
abstract class Demo01{
Demo01(){}
void hehe() {}
abstract void hai();
// - The abstract method hai in type Demo01 can only be defined by an abstract class
//有抽象方法的类必须是抽象类
// - Abstract methods do not specify a body
//抽象方法不能有方法体
}
class Demo01Zi extends Demo01{
Demo01Zi(){
super();
}
void hai() {}
}
abstract class Demo02{
void hehe() {}
}
//某公司的雇员分为以下若干类:
//Employee:这是所有员工总的父类,属性:员工的姓名,员工的生日月份。
// 方法:getSalary(int month) 根据参数月份来确定工资,如果该月员工过生日,则公司会额外奖励100元。
abstract class Employee{
String name;
int birthMonth;
//此Employee类是所有员工的类父类---此类中的成员 是所有员工类共同的成员
//员工都有getSalary 不同员工的工资结构不同
abstract double getSalary(int month);//信息不完整 需要发多少工资 不明确 此方法功能无法实现 方法体没法写
void hai() {}
}
class HourlyEmployee extends Employee{
void hai() {}
double hourSalary;
int hours;
//子类根据自己的需求 实现父类的抽象方法
double getSalary(int month) {
hai();
super.hai();
return hours*hourSalary+(hours>160?(hours-160)*0.5*hourSalary:0)+(month==birthMonth?100:0);
}
}
抽象练习
public class LianXi01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Circle c=new Circle();
c.r=12;
System.out.println("周长="+c.qiuZC());
System.out.println("面积="+c.qiuMJ());
}
}
//创建一个形状类shape:有求周长和求面积方法
//Shape类没有必要创建对象 信息不完整
abstract class Shape{
//求周长方法:信息不完整(不知道具体的形状 没有公式) 方法功能无法实现 应该写成抽象方法
abstract double qiuZC();
abstract double qiuMJ();
}
//shape类存在的意义:不是创建对象 而是为子类定义规范
//(必须有求周长和求面积的方法 方法声明必须和我一样 但方法体根据自己需求写)
//创建子类circle类:有属性半径和圆周率
class Circle extends Shape{
double r;
final double PI=3.14;
//根据自己的需求 实现抽象方法
double qiuZC() {
return 2*PI*r;
}
double qiuMJ() {
return r*r*PI;
}
}
//创建子类rect类:有属性长和宽
class Rect extends Shape{
double chang;
double kuan;
//根据自己的需求 实现抽象方法
double qiuZC() {
return 2*(chang+kuan);
}
double qiuMJ() {
return chang*kuan;
}
}
多态的概念(什么是多态)
public class Demo02DuoTai {
public static void main(String[] args) {
Fu fu=new Fu();//正宗的父类对象
Zi zi=new Zi();
Fu fuzi=new Zi();//引用是父类类型 对象是子类类型
//多态:等号两边多种形态
// 给子类对象起个父类类型的名字、把子类对象伪装成父类类型、让父类引用指向子类对象 }
}
class Fu{
String name="fu-name";
int a=1;
void show() {System.err.println("fu--show方法");}
void hai() {System.out.println("fu-hai方法");}
}
class Zi extends Fu{
String name="zi----name";
int b=1;
void show() {System.err.println("zi------show方法");}
void nihao() {System.out.println("子类特有方法");}
}
多态的特点(多态的对象有什么特点)
public class Demo02DuoTai {
public static void main(String[] args) {
Fu fu=new Fu();//正宗的父类对象
Zi zi=new Zi();
Fu fuzi=new Zi();//引用是父类类型 对象是子类类型
//多态:等号两边多种形态
// 给子类对象起个父类类型的名字、把子类对象伪装成父类类型、让父类引用指向子类对象
System.out.println(fuzi.a);
//多态对象:被伪装成父类类型的子类对象 起了父类类型名字的子类对象
//父亲:脸上标志瘊子 吸烟--吸水烟袋 吃饭
//儿子:脸上标志刀疤 红头发 吸烟--吸华子 吃饭 玩游戏
//把儿子伪装成父亲:::脸上是瘊子 不能有红头 吸烟--吸华子 吃饭 不能玩游戏
System.out.println(fuzi.a);//父类继承的属性a
System.out.println(fuzi.name);
//System.out.println(fuzi.b); //子类特有成员变量被隐藏
//fuzi.nihao(); //子类特有成员方法被隐藏
fuzi.hai();//父类继承的方法
fuzi.show();//zi------show方法
//把子类对象伪装成父类类型::
// 隐藏子类特有的成员+
// 隐藏子类重新定义的成员变量+
// 显示父类被重写定义而隐藏的成员变量
//多态对象的特点:除了重写的方法 其他和父类对象完全相同
}
}
class Fu{
String name="fu-name";
int a=1;
void show() {System.err.println("fu--show方法");}
void hai() {System.out.println("fu-hai方法");}
}
class Zi extends Fu{
String name="zi----name";
int b=1;
void show() {System.err.println("zi------show方法");}
void nihao() {System.out.println("子类特有方法");}
}
多态的使用(什么时候使用多态)
使用场景一:
案例:动物园:狗猫兔子 都有吃和运动功能 ,写方法实现喂所有动物
不使用多态
public class Demo03DuoTaiUse01 { public static void main(String[] args) { } //static void wei(Dog d) 只能喂狗 static void wei(Dog1 d) { d.eat(); d.yunDong(); } static void wei(Cat1 d) { d.eat(); d.yunDong(); } static void wei(Rabbit1 d) { d.eat(); d.yunDong(); } /*不使用多态缺点: * 1 代码复用性差:需要为每种动物都写一个wei方法 * 2 模块之间的耦合度高:饲养员类与dog/cat/rabbit类 关联紧密 * 3 扩展性差:如果有新的动物 需要更改饲养员类 * */ } class Dog1{ private String name; Dog1(String name){this.name=name;} void eat() {System.out.println("狗:开始吃骨头!!");} void yunDong() {System.out.println("狗:吃饱抓老鼠");} } class Cat1{ private String name; Cat1(String name){this.name=name;} void eat() {System.out.println("猫:开始吃鱼!!");} void yunDong() {System.out.println("猫:吃饱晒太阳");} } class Rabbit1{ private String name; Rabbit1(String name){this.name=name;} void eat() {System.out.println("兔子:开始吃胡萝卜!!");} void yunDong() {System.out.println("兔子:吃饱了挖洞");} }
使用多态
public class Demo03DuoTaiUse02 { public static void main(String[] args) { Dog2 d=new Dog2("二哈"); wei(d);//等价于Animal2 a=d; 多态 Cat2 c=new Cat2("波斯猫"); wei(c); } //4 定义方法时 参数列表定义为父类类型 此方法就可以接受所有子类类型的对象 static void wei(Animal2 a) { a.eat(); a.yunDong(); } /* * 使用多态场景1:定义方法时 参数列表定义为父类类型 这样就可以传递任意子类类型的对象 * 好处: * 1 代码复用性强:所有animal的子类都可以使用wei(Animal2 a) 方法 * 2 降低模块之间的耦合度:饲养员类只与Animal2类 关联 * 3 提高程序的扩展性:如果有新的动物 不需要更改饲养员类 只要新动物继承Animal2类即可 使用wei方法 * */ } //1 创建父类:抽取所有子类的共同属性和功能 abstract class Animal2{ //信息不完整 eat功能的方法体无法实现 abstract void eat() ; abstract void yunDong() ; } //2 所有子类继承父类 class Dog2 extends Animal2{ private String name; Dog2(String name){this.name=name;} //3 根据子类需求实现所有的抽象方法 void eat() {System.out.println("狗:"+name+"开始吃骨头!!");} //3 根据子类需求实现所有的抽象方法 void yunDong() {System.out.println("狗:"+name+"吃饱抓老鼠");} } class Cat2 extends Animal2{ private String name; Cat2(String name){this.name=name;} void eat() {System.out.println("猫:"+name+"开始吃鱼!!");} void yunDong() {System.out.println("猫:"+name+"吃饱晒太阳");} } class Rabbit2 extends Animal2{ private String name; Rabbit2(String name){this.name=name;} void eat() {System.out.println("兔子:"+name+"开始吃胡萝卜!!");} void yunDong() {System.out.println("兔子:"+name+"吃饱了挖洞");} }
总结:定义方参数列表时 定义为父类类型 就可以传递任意子类类型的对象
使用场景二:
案例:定义一个台灯类:Lamp: 有方法on 可以开启灯泡的发亮功能,灯泡有红灯泡和绿灯泡
不使用多态
public class Demo04DuoTaiUse01 { public static void main(String[] args) { RedBulb r=new RedBulb("红灯1号"); GreenBulb g=new GreenBulb("绿灯1号"); Lamp lamp=new Lamp(); lamp.red=r; lamp.on(); lamp.green=g; lamp.on(); } } /*不使用多态缺点: 1 代码复用性差:需要在台灯类中为每种灯泡定义属性 *2 模块之间的耦合度高:台灯类中直接关联了所有的灯泡类型 *3 程序的扩展性差:如果有新的灯泡 需要在lamp中添加新的属性 并且还需要修改on方法 * */ class RedBulb{ private String name; public RedBulb(String name) { this.name = name; } void shine() {System.out.println("红灯泡:"+name+"正在发亮!!!红光 红光");} } class GreenBulb{ private String name; public GreenBulb(String name) { this.name = name; } void shine() {System.out.println("绿灯泡:"+name+"正在发亮!!!绿光 绿光 绿光 绿光 绿光 绿光 绿光");} } class Lamp{ //灯泡是台灯一部分:定义两个属性来分别接受给当前台灯关联的灯泡对象 RedBulb red; GreenBulb green; void on() { if(red!=null) {red.shine();} if(green!=null) {green.shine();} } }
使用多态
public class Demo04DuoTaiUse02 { public static void main(String[] args) { // TODO Auto-generated method stub RedBulb2 r=new RedBulb2("红灯1号"); GreenBulb2 g=new GreenBulb2("绿灯1号"); Lamp2 l=new Lamp2(); l.b=r;//等价于:Bulb2 b=new RedBulb2("红灯1号"); //多态 l.on(); l.b=g;//等价于:Bulb2 b=new GreenBulb2("绿灯1号");//多态 l.on(); } //多态使用场景2:定义类的成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象 } //1 创建父类:提取所有子类的共同方法和属性来形成父类 abstract class Bulb2{ String name; public Bulb2(String name) { this.name = name; } abstract void shine(); } //2 所有子类继承父类 class RedBulb2 extends Bulb2{ public RedBulb2(String name) { super(name); } //3 根据子类需求 实现父类的抽象方法 void shine() {System.out.println("红灯泡:"+name+"正在发亮!!!红光 红光 红光 红光");} } class GreenBulb2 extends Bulb2{ public GreenBulb2(String name) { super(name); } void shine() {System.out.println("绿灯泡:"+name+"正在发亮!!!绿光 绿光 绿光 绿光 绿光 绿光 绿光");} } class Lamp2{ //4 定义成员变量时:如果定义为具体的子类类型 就只能接受一种子类类型的对象 // 需要定义为父类类型 Bulb2 b; void on() { if(b!=null) {b.shine();} } }
多态使用场景2:定义类的成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象
使用场景三
案例:三个类型:Circle rect square 都有自己的属性和求周长求面积方法
写方法 参数是int n;n>0 返回一个正方形, n<0 返回一个长方形, n==0 返回一个圆形只能通过多态来实现
public class Demo05DuoTaiUse { public static void main(String[] args) { // TODO Auto-generated method stub Shape2 s=getShape(1);//多态 } //返回的对象是三种类型 返回值类型只能声明为父类类型 public static Shape2 getShape(int n) { if(n==0) return new Circle2(1); if(n>0) return new Square2(1); return new Rect2(3, 1); } } abstract class Shape2{ abstract double qiuZC(); abstract double qiuMJ(); } class Circle2 extends Shape2{ public Circle2(double r) {this.r = r;} double r; final double PI=3.14; double qiuZC() {return 2*PI*r;} double qiuMJ() {return r*PI*r;} } class Rect2 extends Shape2{ double chang,kuan; public Rect2(double chang, double kuan) { this.chang = chang;this.kuan = kuan; } double qiuZC() {return 2*(chang+kuan);} double qiuMJ() {return chang*kuan;} } class Square2 extends Shape2{ double bianChang; public Square2(double bianChang) { this.bianChang = bianChang; } double qiuZC() {return 4*bianChang;} double qiuMJ() {return bianChang*bianChang;} }
使用场景3:定义方法返回值类型时 定义为父类类型 这样就可以返回任意子类类型的对象
使用场景四:
案例:三个类型:Circle rect square 都有自己的属性和求周长求面积方法
创建一个数组 装2个圆 2个长方形 2个正方形
只能通过多态实现
public class Demo06DuoTaiUse { public static void main(String[] args) { //定义数组前先明确:元素类型+元素个数 //元素类型只能定义为父类类型---元素是三种类型 //元素个数---6 Shape3[] arr=new Shape3[6]; arr[0]=new Square3(1);//多态 arr[1]=new Circle3(2); arr[2]=new Rect3(3, 1); arr[3]=new Square3(11); arr[4]=new Circle3(21); arr[5]=new Rect3(31, 11); for (int i = 0; i < arr.length; i++) { Shape3 s=arr[i]; System.out.println("周长:"+s.qiuZC()); System.out.println("面积:"+s.qiuMJ()); } } } abstract class Shape3{ abstract double qiuZC(); abstract double qiuMJ(); } class Circle3 extends Shape3{ public Circle3(double r) {this.r = r;} double r; final double PI=3.14; double qiuZC() {return 2*PI*r;} double qiuMJ() {return r*PI*r;} } class Rect3 extends Shape3{ double chang,kuan; public Rect3(double chang, double kuan) { this.chang = chang;this.kuan = kuan; } double qiuZC() {return 2*(chang+kuan);} double qiuMJ() {return chang*kuan;} } class Square3 extends Shape3{ double bianChang; public Square3(double bianChang) { this.bianChang = bianChang; } double qiuZC() {return 4*bianChang;} double qiuMJ() {return bianChang*bianChang;} }
使用创建4:定义数组元素类型时 定义为父类类型 这样就可以装任意子类类型的对象。
总结
/*
* 使用创建1:定义方法参数列表时 定义为父类类型 这样就可以传递任意子类类型的对象
* 使用创建2:定义类的成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象
* 使用创建3:定义方法返回值类型时 定义为父类类型 这样就可以返回任意子类类型的对象
* 使用创建4:定义数组元素类型时 定义为父类类型 这样就可以装任意子类类型的对象
*
* 什么是多态:给子类对象起个父类类型的名字
* 多态对象有什么特点:除了重写的方法 其他和父类对象完全相同
* 什么时候使用多态:
* 总而言之:定义方法参数列表、方法返回值类型、类的成员变量、数组元素类型时 都定义为父类类
型,这样就可以传递、返回、赋值、装任意子类类型的对象
*
* */
向上转型
把子类对象伪装成父类类型
给子类对象起个父类类型的引用
多态前提:
继承:子类和父类定义关联关系
向上转型:父类引用指向子类对象
重写:多态对象除了重写的方法 其他和父类对象完全相同
多态内存图
package
package com.zut.oop;
public class Demo01Package {
/*
* package:包
*
* 作用:对项目的资源进行分类 类似于文件夹
命名:域名倒写
* 注意:1 package声明必须是源文件的第一个语句
* 2 常用的基础类库的包:
* io--流
* sql--数据库
* text---文本
* net---网络
* lang---最基础的包
* util---工具类包
* math---数学运算
* 3 类的全称:包名.类名
* 不加包名 默认是本包
* */
public static void main(String[] args) {
Demo01Package dp;
com.zhiyou100.day04_oop.Demo01Package dp2;
}
}
Interface
/* 抽象类:不是用于创建对象 而是为子类的创建定义规范
* 概念:当一个类的所有方法都是抽象方法时---接口
* interface: 为实现类定义规范
* 和抽象类的使用完全相同
* 接口关键字:interface
* 特点:1 接口中的成员变量默认修饰符:public static final
* 2 接口中的方法默认修饰符:public abstract
* 3 类"继承"接口--类实现接口
* 此类称之为接口的实现类 使用关键字implements
* 格式:class 实现类 implements 接口{}
* 4 java支持一个实现类可以同时实现多个接口 同时不影响继承父类
* class Demo04Zi1 extends Fu4 implements TestInterface,TestInte1
* 5 接口没有构造方法
* 6 接口的实现类需要实现所有的抽象方法 否则是抽象类
* 7 接口的作用:定义引用(指向的是实现类对象---多态)+为实现类定义规范
* 8 接口与接口之间是多继承关系
* interface TestInte3 extends TestInte1,TestInte2
*
* 接口和类的关系
* 关系 关键字 案例
* 类与类之间 单继承 extends class Zi extends Fu{}
* 类与接口之间 多实现 implements class Zi implements Inte1,Inte2{}
* 接口与接口之间 多继承 extends interface InteZi extends Inte2,Inte3{}
*
*
*
* */
package com.zhiyou100.day04_oop;
public class Demo04Interface {
/* 抽象类:不是用于创建对象 而是为子类的创建定义规范
概念:当一个类的所有方法都是抽象方法时---接口
interface: 为实现类定义规范
和抽象类的使用完全相同
接口关键字:interface
特点:1 接口中的成员变量默认修饰符:public static final
2 接口中的方法默认修饰符:public abstract
3 类"继承"接口--类实现接口
此类称之为接口的实现类 使用关键字implements
格式:class 实现类 implements 接口{}
4 java支持一个实现类可以同时实现多个接口 同时不影响继承父类
class Demo04Zi1 extends Fu4 implements TestInterface,TestInte1
5 接口没有构造方法
6 接口的实现类需要实现所有的抽象方法 否则是抽象类
7 接口的作用:定义引用(指向的是实现类对象---多态)+为实现类定义规范
8 接口与接口之间是多继承关系
interface TestInte3 extends TestInte1,TestInte2
接口和类的关系
关系 关键字 案例
类与类之间 单继承 extends class Zi extends Fu{}
类与接口之间 多实现 implements class Zi implements Inte1,Inte2{}
接口与接口之间 多继承 extends interface InteZi extends Inte2,Inte3{}
*/
public static void main(String[] args) {
System.out.println(TestInterface.a);
}
}
class Demo04Zi1 extends Fu4 implements TestInterface,TestInte1{
public void hai() {}
public void nihao() {}
}
interface TestInte1{
int a=1;
void nihao();
}
interface TestInte2{
int b=1;
void hai();
}
interface TestInte3 extends TestInte1,TestInte2{
// int a=1;
// void nihao();
// int b=1;
// void hai();
}
class Fu4{}
抽象类和接口的区别
抽象类和接口的区别
概念:抽象类:abstract class
接口:interface
相同之处:
1 都可以抽象方法
2 都只能定义引用 不能创建对象
3 存在的意义都是为子类/实现类的创建定义规范
不同之处:
1 抽象类中可以没有抽象方法
接口中的方法默认修饰符:public abstract
2 抽象类是类有构造方法
接口没有构造方法
3 接口中的属性默认修饰符:public static final 不能有实例成员变量
4 子类继承抽象类只能单继承 使用关键字extends
实现类可以同时实现多个接口 使用关键字implements
接口之间是多继承关系 使用关键字extends
import
在java源文件中引入其他包的类
package com.zut.oop;
import com.zut.oop_fuxi.Demo01Abstract;
//当前文件中com.zut.oop_fuxi.Demo01Abstract可以简写为Demo01Abstract
//所有java源文件默认引入包:java.lang
public class Demo02Import {
public static void main(String[] args) {
Demo01Package pd;//提到的类 不加包名 默认是本包
com.zut.oop.Demo01Package pd2;
com.zut.oop_fuxi.Demo01Abstract dba11
=new com.zut.oop_fuxi.Demo01Abstract();
com.zut.oop_fuxi.Demo01Abstract dba12
=new com.zut.oop_fuxi.Demo01Abstract();
com.zut.oop_fuxi.Demo01Abstract dba13
=new com.zut.oop_fuxi.Demo01Abstract();
Demo01Abstract dba14=new Demo01Abstract();
java.lang.String s;
}
}
instanceof
public class Demo03Instanceof {
/*
* instanceof 关键字:运算符
* 判断对象的具体类型:
* */
public static void main(String[] args) {
Animal[] array=getArr();
for (int i = 0; i < array.length; i++) {
Animal a=array[i];//使用者只能把元素作为父类类型来使用
a.eat();
//获取子类特有的成员::::
//需要把:伪装成父类类型的多态对象打回本来的子类类型---向下转换
if(a instanceof Cat) {//判断多态对象的本质类型
Cat c=(Cat)a;//向下转型格式: 子类类型引用=(子类类型)多态对象;
c.saiTaiYang();
}
if(a instanceof Dog) {//在向下转型前 必须通过instanceof 判断多态对象的具体类型
Dog d=(Dog)a;
d.zhuoLaoShu();
}
// Cat c=(Cat)a;//向下转型 //ClassCastException
// c.saiTaiYang();
}
Animal a=new Animal("动物1");
Cat c=new Cat("cat1");
Animal a1=c;//通过a1访问 就是多态对象 通过c访问就是子类对象
System.out.println("a1 instanceof Animal ="+(a1 instanceof Animal));//true
System.out.println("a1 instanceof Dog ="+(a1 instanceof Dog));//false
System.out.println("a1 instanceof Cat ="+(a1 instanceof Cat));//true
}
public static Animal[] getArr() {
Animal[] arr=new Animal[6];
arr[0]=new Animal("动物1号");
arr[1]=new Cat("波斯猫");
arr[2]=new Dog("二哈");
arr[3]=new Animal("动物2号");
arr[4]=new Cat("大脸猫");
arr[5]=new Dog("大黄");
return arr;
}
}
class Animal{
String name;
public Animal(String name) {this.name=name;}
void eat() {System.out.println(name+"动物--食草动物+食肉动物");}
}
class Cat extends Animal{
public Cat(String name) {super(name);}
void eat() {
System.out.println(name+"猫吃鱼!");
}
void saiTaiYang(){
System.out.println(name+"猫在晒太阳!");
}
}
class Dog extends Animal{
public Dog(String name) {super(name);}
void eat() {
System.out.println(name+"狗吃骨头!");
}
void zhuoLaoShu(){
System.out.println(name+"狗在捉老鼠!");
}
}
a.eat();
//获取子类特有的成员::::
//需要把:伪装成父类类型的多态对象打回本来的子类类型---向下转换
if(a instanceof Cat) {//判断多态对象的本质类型
Cat c=(Cat)a;//向下转型格式: 子类类型引用=(子类类型)多态对象;
c.saiTaiYang();
}
if(a instanceof Dog) {//在向下转型前 必须通过instanceof 判断多态对象的具体类型
Dog d=(Dog)a;
d.zhuoLaoShu();
}
// Cat c=(Cat)a;//向下转型 //ClassCastException
// c.saiTaiYang();
}
Animal a=new Animal("动物1");
Cat c=new Cat("cat1");
Animal a1=c;//通过a1访问 就是多态对象 通过c访问就是子类对象
System.out.println("a1 instanceof Animal ="+(a1 instanceof Animal));//true
System.out.println("a1 instanceof Dog ="+(a1 instanceof Dog));//false
System.out.println("a1 instanceof Cat ="+(a1 instanceof Cat));//true
}
public static Animal[] getArr() {
Animal[] arr=new Animal[6];
arr[0]=new Animal("动物1号");
arr[1]=new Cat("波斯猫");
arr[2]=new Dog("二哈");
arr[3]=new Animal("动物2号");
arr[4]=new Cat("大脸猫");
arr[5]=new Dog("大黄");
return arr;
}
}
class Animal{
String name;
public Animal(String name) {this.name=name;}
void eat() {System.out.println(name+"动物--食草动物+食肉动物");}
}
class Cat extends Animal{
public Cat(String name) {super(name);}
void eat() {
System.out.println(name+"猫吃鱼!");
}
void saiTaiYang(){
System.out.println(name+"猫在晒太阳!");
}
}
class Dog extends Animal{
public Dog(String name) {super(name);}
void eat() {
System.out.println(name+"狗吃骨头!");
}
void zhuoLaoShu(){
System.out.println(name+"狗在捉老鼠!");
}
}