面向对象(oop)
1.初识面向对象
- 方法回顾和加深
类和对象的关系
- 对象的创建分析
创建与初始化对象
构造器详解
创建对象 内存分析
小结:
- 面向对象三大特性
封装
继承
多态
抽象类
接口
- 内部类
1.初识面向对象
- 面向过程思想
- 步骤清晰简单,第一步做什么,第二步做什么..
- 面向过程适合处理一些较为简单的问题
- 面向对象思维
- 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题。
- 对于描述复杂的事物,为了从宏观上把握,从整体上分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
- 面向对象编程(oop)
- 面向对象编程的本质就是:以类的方式组织代码,以对象的方式组织(封装)数据。
- 抽象
- 三大特征
- 从认识的角度考虑是先有对象后有类。对象,是具体的事物。类是抽象的,是对对象的抽象
- 从代码运行角度考虑是先有类后有对象。类是对象的模板
2. 方法回顾和加深
-
方法的定义:
- 修饰符
- 返回类型
- break:跳出switch,结束循环 continue。结束方法 返回一个值return
- 方法名:注意规范就ok 见名知意
- 参数列表:(参数类型,参数名)...
- 异常抛出:疑问,后面讲解
-
方法的调用
静态方法不可以直接调用同一个类中的非静态方法:因为静态方法是和类一块存在的,也就是有类的时候就有了静态方法。但是非静态方法是跟随类实例化的(对象)也就是有了new的类对象之后,才有非静态方法。
当一个已经存在的调用一个不存在的,所以就会报错。
同时:一个类中非静态可以直接调用非静态。静态可以直接调用静态。
/**
* @Auther: 王海新
* @Date: 2021/1/31 15:29
* @Description: 值传递
*/
public class demo1 {
public static void main(String[] args) {
int a = 1;
System.out.println(a);
test(1);
System.out.println(a);
}
private static void test(int i) {
i = 10;
}
}
两个输出结果都为1。.因为是值传递,它只是把数值传递过去。原来的a并没与变。
引用传递:
package com.wang.opp.demo1;
/**
* @Auther: 王海新
* @Date: 2021/1/31 15:59
* @Description: 引用传递 对象 : 本质还是值传递。我们之前说过,java只有值传递。
*/
public class demo2 {
public static void main(String[] args) {
Perosn perosn = new Perosn();
System.out.println(perosn.name);
test(perosn);
System.out.println(perosn.name);
}
private static void test(Perosn i) {
//i是一个对象。指向了上面的Perosn perosn = new Perosn();就像是一个具体的人,
// 可以改变它的属性,所以再次输出时,这个对象的name就改变了
i.name = "海新";
}
}
/**
* @Description: 定义一个类。在一个文件中可以有多个类,但只能有一个public修饰的类。
* @Param:
* @return:
* @Author: 王海新
* @Date:
*/
class Perosn{
String name;
}
上述代码传递对象时,就可以改变了其中的name。可能大家还要些疑惑。之后我们会从对象 和内存两个方法再做详细解释。
- this关键字(先打个照面,之后方法继承和多态时讲解。)
类和对象的关系
- 类是一种抽象的数据类型,它是对某一类事物整体描述/定义。但并不能够代表某一个具体的事物
- 动物,植物,手机,电脑...(类就是这样,表示一类,但不能代表某一个具体的动物,植物。。。)
- Person类,Pet类,Car类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为
- 对象是抽象概念的具体实例
- 张三就是人的具体实例,张三家的旺财就是狗的一个具体实例。
- 能够体现出特点,展示出功能的是具体的实例,而不是一个抽象的概念
我们可以将这些思想转化为代码实现。
3. 对象的创建分析
创建与初始化对象
- 使用new关键字创建对象
- 使用new关键字创建的时候,除了分配内存空间之外,还会给 创建好的对象进行默认的初始化以及对类中构造器的调用。
- 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有一下两个特点:
- 必须和类的名字相同
- 必须没有返回类型,也不能写void
- 构造器必须要掌握
- 类实例化后会返回一个自己的对象!这时才会给这个对象分配空间,初始化以及对类中构造器的调用。
- 以类的方式组织代码,以对象的组织(封装)数据。
构造器详解
- 一个类即使什么都不写,它也会有一个方法。就是构造器。
- 与类名相同,没有返回值 public修饰。
- 一个类可以有多个构造器。但是各个构造器的参数个数,或者类型必须不同。
- 默认有一个空参构造器。如果创建了有参构造器。空参构造器就不会默认创建。如果需要调用无参,需要手动声明一个空参构造器。
- 使用new关键字创建对象,本质是在调用构造器。
- 当创建的时候,传递了什么参数,就会调用相同类型的构造器。
- 构造器用来初始化值
- idea快捷键:alt + insert =》constructor 面里面可以选生成有参或无参的构造器
创建对象 内存分析
package com.wang.opp;
/**
* @Auther: 王海新
* @Date: 2021/2/1 12:14
* @Description: 内存分析
*/
public class demo2 {
public static void main(String[] args) {
Pet dog= new Pet();
dog.name = "旺财";
dog.age = 1;
Pet cat= new Pet();
cat.name = "加菲猫";
cat.age = 1;
}
}
/**
* @Description: 动物类
* @Param:
* @return:
* @Author: 王海新
* @Date:
*/
class Pet{
String name;
int age;
public void shot(){
System.out.println("叫了一声");
}
}
如以上代码在内存中的分析:
小结:
-
类与对象
类是一个模板:抽象。对象是一个具体的实例
-
方法:
定义,调用!
-
对象的引用
引用类型
基本类型(8种)
对象是通过引用来操作的:栈--》堆
-
属性:字段(Field) 成员变量
默认初始化
数字:0 0.0
char:u0000
boolean:false
引用:null
修饰符 属性类型 属性名 = 属性值;
-
对象的创建和使用
- 必须使用new 关键字创建对象,构造器 Person haixin = new Person();
- 对象的属性: haixin.name
- 对象的方法: haixin.sleep();
-
类:
静态的属性: 属性
动态的行为: 方法
封装 继承 多态
4. 面向对象三大特性
封装
class Pet{
private String name;
private int age;
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 void shot(){
System.out.println("叫了一声");
}
}
如上 调用相应的方法set给属性赋值。用get获取值
/**
* @Auther: 王海新
* @Date: 2021/2/1 12:14
* @Description: 内存分析
*/
public class demo2 {
public static void main(String[] args) {
Pet dog= new Pet();
dog.setName("旺财");
dog.setAge(1);
Pet cat= new Pet();
dog.setName("加菲猫");
dog.setAge(1);
}
}
继承
- 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
- extend的意思是“扩展”。子类是父类的扩展。
- JAVA中只有单继承,没有多继承!一个儿子只能有一个爸爸。一个爸爸可以有多个儿子
- 继承是类和类之间的关系。除此之外类和类之间的关系还有依赖,组合,聚合等。
- 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类用extends来表示
- 子类和父类之间,从意义上讲应该具有is a 的关系。
- 私有的东西无法被继承
快捷键:Ctrl + h 可以查看当前类的继承关系
-
object类
object类是所有类的父类。我们平时定义的类都默认继承了object类。所以我们刚刚定义的类不写任何东西。在使用其对象的时候,也会有很多方法 属性 可以直接使用。
-
super
当子类重载了父类的方法或者变量的时候。用super来表示调用的是父类的。默认是调用子类的。也可以用this.来表示当前类的东西。
super.name 就表示调用的是父类的name
- 如果父类私有的(private修饰)。则也无法调用。
- 同时,super() 表示调用父类的构造器。super(int 1) 就表示调用父类的有参构造器。
- super()在子类的构造器第一行,如果调用this(有参或无参)也需要在第一行。
- 默认调用了父类的无参构造器。并且super必须在第一行。如果父类没有无参构造器就会报错(所以前面我们要求,在写了有参构造器之后,手动写一个无参构造器。避免之后出错)
- 通过在构造器中打印语句。我们知道先执行了父类 再执行子类
-
super注意点:
- super调用父类的构造方法,必须在调用方法的第一个
- super必须只能出现在方法或者构造方法中
- super和this不能同时调用构造方法!
-
VS this
this:本身调用者这个对象
super: 代表父类对象的应用
this:没有继承也可以使用
super:只能在继承条件才可以使用
this()本身的构造器
super() 父类的构造器
-
重写
A(extend)继承B
假如入A和b都定义了public static void test(){
}方法
A a = new A();
a.test();//结果打印A 中的test
B b = new A();
b.test();//执行的是B中的test
假如入A和b都定义了public void test(){
}方法
A a = new A();
a.test();//结果打印A 中的test
B b = new A();//父类的引用指向了子类
b.test();//结果打印A 中的test
总结:只有在非静态方法中才能实现真正的重写,静态方法是重写不了的。
非静态的不是私有的方法 才可以重写
idea有提示,只有在打断点的位置出现一个O加一个向上的箭头,才表示重写成功了
重写是指重写父类中的
重载是指本 类中方法名相同,参数列表不同
-
方法名必须相同
-
参数列表必须相同
-
修饰符:范围可以扩大但不能缩小:(修饰符这部分我们还没有全部讲到,大家可以这样记忆。子类的修饰符权限必须大于等于父类)
public>Protected>Default>private
-
抛出异常:范围:可以被缩小但不能扩大:(子类的异常范围只能等于小于父类)
ClassNotFoundExeception == >Exception(大)
重写,子类的方法和父类的方法必须要一致:方法体不同!
父类的功能,子类不一定都需要,或者不一定都满足
Alt + insert =》override
多态
动态编译:类型:可扩展性
- 多态注意事项:
- 多态是方法的多态,属性没有多态
- 父类和子类,有联系 类型转换异常!ClasCastException!
- 存在条件:继承关系,方法需要重写,父类引用指向子类对象!
- Father f1 = new son();
- 不可以继承的方法和常量(无法继承,自然没办法实现多态)
- static 方法:属于类,它不属于实例
- final 常量
- private方法
- 多态
- 既同一方法可以根据发送对象的不同而采用多种不同的行为方式
- 一个对象的实际类型是确定的,但可以指向对象的引用类型的类型有很多种(父类,有关系的类)
- 多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
- 注意:多态是方法的多态,属性没有多态性
- instanceof (类型转换)引用类型
package com.wang.opp.demo3;
/**
* @Auther: 王海新
* @Date: 2021/2/2 16:27
* @Description:
*/
public class Persion {
public void run(){
System.out.println("Persion");
}
}
package com.wang.opp.demo3;
/**
* @Auther: 王海新
* @Date: 2021/2/2 16:27
* @Description:
*/
public class Student extends Persion {
@Override
public void run() {
System.out.println("Student");
}
public void eat() {
System.out.println("吃");
}
}
package com.wang.opp.demo3;
/**
* @Auther: 王海新
* @Date: 2021/2/2 16:26
* @Description: 启动类
*/
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student
//new Student
Student student = new Student();
//可以指向的引用类型就不确定了:父类的引用指向子类
Persion persion = new Student();
Object object = new Student();
//对象能执行那边的方法主要看对象左边的类型:和右边关系不大
student.run();
//父类型可以调用子类型,但是不能调用子类独有的方法。
persion.run();//结果都是执行子类重写后的方法。
}
}
-
类型转换,我们可以通过类型转换instanceof,来判断两个类是否可以进行强制转换
A extends B
C extends B
Object object = new A();
sout(object instanceof A);//true
sout(object instanceof Object );//true
sout(object instanceof B);//true
sout(object instanceof C);//flase
object的引用指向的是A,和C并没有直接关系。所以打印结果为false。但是不报错(因为C的父类的父类也是Object
sout(A Iinstanceof B);
//直接报类型转换错误。因为A和B并没有一点关系
我们可以通过instanceof是否编译通过,判断两者是否有父子关系
-
类型转换:
- 子类可以直接转换为父类。父类转换为子类。需要强转
- 子类转换为父类(强转),会丢失自己独有的一些方法!父类转化为子类,会丢失被子类重写的方法(执行子类中的重写方法)。
- 方便方法的调用,将一些类转换就可以调用不同的方法。减少重复的代码!简洁
抽象:继承 封装 多态 面向对象的三大基本特征都是为了抽象
抽象也是编程思想
static关键字详解:
package com.wang.opp.demo4;
/**
* @Auther: 王海新
* @Date: 2021/2/3 17:16
* @Description: 静态代码块
*/
public class Persion {
public Persion() {//3.第三次执行,每次调用都执行
System.out.println("构造函数");
}
{//2,第二执行,每次调用都执行。一般用来赋初始值
System.out.println("匿名代码块");
}
static {//1.最先执行,且仅执行一次
System.out.println("静态代码块");
}
public static void main(String[] args) {
Persion persion = new Persion();
System.out.println("= ============");
Persion persion1 = new Persion();
}
}
同时,用final修饰的类,不可以再被继承。
抽象类
package com.wang.opp.demo5;
/**
* @Auther: 王海新
* @Date: 2021/2/3 17:41
* @Description: 抽象类,因为单继承的原因,抽象类用的并没有下面要讲的接口用的多
*/
public abstract class Action {
public abstract void run();
public void say(){
System.out.println("hah");
}
/*
抽象类就是一个约束。只定义方法名字。不定义具体实现。
*/
}
package com.wang.opp.demo5;
/**
* @Auther: 王海新
* @Date: 2021/2/3 17:41
* @Description:
*/
//继承抽象类就必须要重写抽象类中的抽象方法。除非子类也是一个抽象类
public class a extends Action{
@Override
public void run() {
}
}
- 不能new这个抽象类,只能靠子类去实现它:就是一个约束
- 抽象类中可以编写普通的方法
- 抽象方法必须再抽象类中
- 思考题 :
- 抽象类有构造器吗? 有!因为抽象类也属于类。我们可以通过手写一个查看,或者通过将生成的class文件放idea中反编译。看看是否有构造器
- 抽象类存在的意义 抽象出来,提高开发效率,增强相互协作。
接口
- 普通类:只有具体实现
- 抽象类:具体实现和规范(抽象方法)都有!
- 接口:只有规范!自己无法写方法。约束和实现分离:面向接口编程
- 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是...则必须能...”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。
- 接口的本质是契约,就像我们人间的法律一样。制定好后大家都要准守。
- OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计 模式都只针对具体了抽象能力的语言(比如c# c++ java等),就是因为设计模式所研究的,实际上就是如果合理的去抽象。
- 声明类的关键字是class,声明接口的关键字是interface
- 接口中的抽象方法默认都是 public abstract类型的,所以可以省略不用声明。直接写一个 void run(); void say(); 即可
- 接口中的属性默认都是静态常量 public static final修饰。(一般都不在接口中定义常量)
- 接口不能被实例化,接口中没有构造方法
- implements可以是实现多个接口
- 必须要重写接口中的方法
6. 内部类
内部类就是在类的内部再定义一个类,比如A类中定义B类,那么B类相对于A类来说就是内部类,而A相对于B来说就是外部类了
- 成员内部类 定义在类中的类
- 静态内部类 定义
- 局部内部类 定义在方法中的类
- 匿名内部类 在调用的时候,也就是new的时候。不用将实例保存到变量中。而是直接使用。