面向对象 ---- java中“万物皆为对象”
面向对象就是把构成问题的事物分解成一个个对象,建立对象不是为了实现一个步骤,而是为了描述某个事物在解决问题中的行为。
类是面向对象中的一个很重要的概念,因为类是很多个具有相同属性和行为特征的对象所抽象出来的,对象是类的一个实例。
类具有三个特性:封装、继承和多态。
三大特征:
- 封装:核心思想就是“隐藏细节”、“数据安全”,将对象不需要让外界访问的成员变量和方法私有化,只提供符合开发者意愿的公有方法来访问这些数据和逻辑,保证了数据的安全和程序的稳定。所有的内容对外部不可见。
- 继承:将多个类的共性内容抽取出来,放在一个独立的类中,让这个独立的类和其他类产生一种关系, "继承"---关键字 extends
- 多态:宏观角度(现实生活中):一个事物在不同时刻体现的不同形态
微观角度(内存中变化):具体对象在内存中的变化(对象在不同时刻的类型)匿名对象
匿名对象 :
Java中有一个概念:匿名对象: 毋庸置疑,没有名字对象;
我们之前new对象的方式: 类名 对象名 = new 类名() ;
匿名对象的格式:new 类名() ;
匿名对象调用方法: new 类名().成员方法名() ;
好处:节省内存空间,new 类名() ;
匿名对象可以作为参数传递
创建完毕之后,没有栈内存指向,所以使用完毕,立即被GC(垃圾回收器回收)
一般情况:匿名对象使用一次即可,这样不需要过多的去开辟堆内存空间,直接被回收;
//学生类
class Student{
public void study(){
System.out.println("Good Good Study,Day Day Up!");
}
}
//定义StudentDemo类
class StudentDemo{
public void method(Student s){//形式参数是一个Student类型,引用类型
s.study();//调用该方法,应该使用实际参数对象名在访问
}
}
//测试类
public class NoNameDemo {
public static void main(String[] args) {
//要访问StudentDemo类中method方法
//创建StudentDemo类对象|
StudentDemo sd = new StudentDemo() ;
//创建学生对象
Student s = new Student() ;
sd.method(s); //方法里面:形式参数 创建学生了学生对象
System.out.println("---------------------------------");
//使用匿名对象new 类名()
//new 类名().成员方法名() ; //调用自己方法
sd.method(new Student());
System.out.println("---------------------------------");
}
继承
继承的格式
class 父类名{
提供公共的访问方法setXXX()/getXXX()
}
class 子类名 extends 父类名{}
继承的好处:
1)可以提高代码复用性
2)可以提高代码的维护性,后期便于维护,针对子类和父类进行维护(子父关系明确)
3)类与类产生的继承关系,是后面"多态"的前提条件;
继承的特点:
1)在Java语言中,类和的类的关系是一种继承关系,这个继承只能支持"单继承",不支持多继承
class 父{}
class 父2{}
class 子 extends 父,父2{} 多继承:不支持
class 子 extends 父{} :正常的语法格式
2)类和类关系,虽然不支持多继承,但是层层单继承----> 多层继承
继承应该注意的问题:
1.子类继承父类,对于非私有的成员,直接可以继承过来,但是如果私有成员,它可以通过公共的访问可以访问,但是直接访问的;
2.被私有修饰的东西(成员变量/成员方法),只能在当前类访问的;
在继承关系中,构造方法的访问问题(重点)
子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法
为什么?子类继承父类,会用到父类的数据,需要让父类先进行初始化; 一个类初始化的---肯定需要执行构造方法的
面试题:
如果一个父类存在有参构造方法,没有无参构造方法,子类的所有构造会出现什么问题?出现了问题,怎么解决?
子类的所有全部构造方法报错,为什么? 子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法
方案1:
1)手动给出无参构造方法
2)假设,人家现在就不需要让你给出父类的无参构造方法;
就需要让子类的构造方法,显示的访问父类的有参构造方法
----要使用关键字 super:代表父类空间标识(代表的父类对象的地址值引用!)
super() :访问父类的无参构造方法
super(xxx) :访问父类的有参构造方法
这些super一定是在子类构造方法中的第一句话
方案3) 保证子类的所有的构造方法某一个构造方法,让父类初始化完毕即可;
先通过子类的无参构造方法里面---this(xxx):访问本类(子类)有参构造方法
在子类的有参构造方法的第一话:让父类初始化 super(xxx):间接访问父类的有参构造方法
子类继承父类,一定要先执行父类的构造方法,初始化完毕之后;然后才能执行子类的构造方法---分层初始化
//父类
class Fu{
//成员变量名称num
int num = 20 ;
}
//子类
class Zi extends Fu{
//成员变量名称
//int num2 = 30 ;
//int num = 50 ;
//子类的成员方法
/* public void show(){
// System.out.println(num) ;//访问父类的成员变量
// System.out.println(num2) ;//访问本类的成员变量
}*/
//method方法
public void method(){
//局部变量
//int num = 100 ;
System.out.println(num);
}
}
//测试类
public class ExtendsDemo {
public static void main(String[] args) {
//创建子类对象
Zi z = new Zi() ;
//z.show() ;
z.method();
}
}
多态
多态的前提条件 (重点)
1)必须有继承关系(类与类),没有继承关系,不谈多态!
2)必须存在方法重写,子类部分功能要将父类的功能进行覆盖,重写,子类使用自己的功能体现;
举例:
动物都需要吃;
猫和狗/猪/猴子 等等 具体动物,给出具体的吃的体现,所以应该将动物的吃进行重写;
3)必须存在父类引用指向 子类对象 :固定格式
class Fu{}
class Zi extends Fu{}
父类名 对象名 = new 子类名() ; //向上转型:使用的父亲的东西
Fu fu = new Zi() ; //父类引用指向 子类对象
Animal a = new Cat() ;//Cat继承自Animal 猫是动物
多态的成员访问特点
父类名 对象名 = new 子类名() ;
1)成员变量:
编译看左,运行看左 ;
2)成员方法 :非静态
编译看左,运行看后, 因为子类重写了父类的功能!
静态方法: 即使子类出现了和父类一模一样静态方法,不算重写,因为静态方法都是自己类相关的,类成员!
编译看左,运行看左;
3)构造方法:多态的前提条件,有继承关系,跟继承一样,分层初始化
先执行父类的构造方法,然后再是子类的构造方法
多态的弊端:
1)有继承关系了 2)有重写了 3)有父类引用指向子类对象 Fu f = new Zi() ;
无法调用子类的特有功能!
如何解决呢?
方案1:创建自己的子类对象
子类名 对象名 = new 子类名() ;
方案1不好地方:本身Fu fu = new Zi() ;已经开辟堆内存空间了,
Zi zi = new Zi();又要在堆内存开辟空间,消耗内存空间比较大 ;
方案2: 多态的第三个前提条件:父类引用指向子类对象
能不能将 将父类的引用 强制为子类的引用呢?
可以
向下转型
前提必须向上转型Fu fu = new Zi() ;
Zi z = (Zi)fu ; //强转的语法
这样的好处:节省内存空间
什么抽象类?
在一个类中,如果有抽象方法,这个类必须为抽象类
抽象类的特点:
1)不能实例化 (不能创建对象)
2)必须强制子类完成事情:必须将抽象方法重写!
抽象类的子类:
如果子类是一个抽象类, 没有意义(抽象类new不了) (前提条件是这个子类没有它的子类)
研究的抽象类的子类一定会有一个具体类,这个时候通过具体类才能创建对象;
抽象的父类名 对象名 = new 具体的子类名() ; 抽象类多态
抽象类的成员特点:
成员变量:抽象类的成员变量既可以有变量,也可以是自定义常量被final
成员方法:抽象类中既可以有抽象方法,也可也有非抽象方法
构造方法:
既可以定义无参/有参构造方法...
存在抽象类多态,有继承关系,初始化的时候,构造方法----分层初始化---->先父类初始化,子类初始化
abstract 和那些关键字冲突
和private关键字冲突:因为被private私有的成员方法只能在本类访问,而abstract修饰的成员方法
必须强制子类重写,已经超出来的当前类的范围
和final也冲突,被final修的成员方法,不能被重写;而抽象方法强制子类必须重写;
和static也冲突,abstract修饰的方法必须被子类重写,而static修饰的方法,算不上抽象,直接跟类相关的;
abstract关键字 应用范围: 定义在类上---抽象类
定义在方法上----抽象方法
public abstract 返回值类型 方法名(空参/带参...) ;
abstract 返回值类型 方法/名(空参带参...) ;
什么是接口?
接口体现的是事物的一种额外功能 ;
设计理念: 体现的是一种 "like a"的关系
跳高猫
钻火圈狗
之前讲继承的概念--->设计理念体现的是一种"is a"的关系 :什么是什么的一种
水果
香蕉
苹果
橘子
举例:
猫或者狗事物,本身出生之后不具备"跳高","钻火圈"等等这些额外的行为,但是通过驯兽师这些人可以将猫和狗训练出来,经过后期的训练,这些事物就具备了这些额外的行为----->这个事物的扩展功能 ;
Java编码中,体现这些事物本身不具备的功能,要经过一些特殊的实现才能具备功能-----称为 "接口"---关键字 interface
格式的写法
interface 接口名{ //命名规范和类名命名一样,见名知意 "大驼峰命名法"
只能为抽象方法
}
接口的子类----"子实现类"
实现
class 子类名 implements 接口名{
}
接口比抽象类还抽象---->特点:不能实例化
定义一个接口 跳高接口
interface Jump{
/*public void jump(){ //接口中的只能是抽象方法
}*/
public abstract void jump() ;//因为 它默认修饰符 public abstract:可以省略不写
}
//跳高猫
class Cat implements Jump{
@Override
public void jump() {
System.out.println("猫可以跳高了");
}
}
//测试类
public class InterfaceDemo {
public static void main(String[] args) {
//Jump jump2 = new Jump() ;//接口不能实例化,需要通过子实现类实例化(必须为具体类)
//测试:接口多态---接口名 对象名 = new 子实现类名();
Jump jump = new Cat() ;
jump.jump();
}
}