面向对象编程基础

面向对象编程

面向对象与面向过程

面向过程思想

  • 步骤清晰简单,第一步做什么,第二步做什… .

  • 面对过程适合处理一些较为简单的问题

面向对象思想

  • 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。

  • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!

对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。

概念

面向对象编程(Object-Oriented Programming, OOP)
面向对象编程的本质就是:以类的方式组织代码,以对象的方式组织(封装)数据。

抽象

三大特性: 封装、继承、多态

从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象。
从代码运行角度考虑是先有类后有对象。类是对象的模板。

类与对象的关系

类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物.

  • 动物、植物、手机、电脑…
  • Person类、 Pet类. Car类等, 这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为。

对象是抽象概念的具体实例

  • 张三就是人的一个具体实例,张三家里的旺财就是狗的一个具体实例。
  • 能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。

创建与初始化对象

使用new关键字创建对象
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。

​ 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下俩个特点:

  1. 必须和类的名字相同

  2. 必须没有返回类型,也不能写void

构造器必须要掌握

创建一个学生类

package com.oop.demo02;
//学生类
public class Student {

    //属性:字段
    String name;
    int age;

    //方法
    public void study(){
        System.out.println(this.name+"在学习");
    }
}

测试类

package com.oop.demo02;
//一个项目应该只存在一个main方法
public class Application {
    public static void main(String[] args) {
    //类:抽象的需要实例化
    // 类实例化后会返回一个自己的对象!
        //student对象就是一个Student类的具体实例!
        Student student = new Student();
        Student xiaoming = new Student();
        Student xiaohong = new Student();
        xiaoming.name="小明";
        xiaoming.age=3;
        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);
        xiaoming.study();//调用Student类的study方法
        xiaohong.name="小红";
        xiaohong.age=3;
        System.out.println(xiaohong.name);
        System.out.println(xiaohong.age);
        xiaohong.study();//调用Student类的study方法

    }
}

结果:

小明
3
小明在学习
小红
3
小红在学习

构造器

1.和类名相同

2.没有返回值

作用:

1.使用new关键字,本质是在调用构造器
2.用来初始化值

注意点:

  1. 定义有参构造后,无参就必须显示定义
package com.oop.demo02;
public class Person {
    //一个类即使什么都不写,他也会存在一个方法
    String name;
    //显示的定义一个无参构造
    public Person(){
    }
    //有参构造:一旦定义了有参构造,无参就必须显示定义
    public Person(String name) {
        this.name = name;
    }
}

创建对象内存分析

在这里插入图片描述
当开始执行Application的main方法时,方法区读取Application类的内容 并将main方法压入栈中,当mian方法执行到new Pet()语句时,方法区读取Pet类并将new出来的对象(dog、cat)的引用变量名压入栈中,将实际生成的对象放入堆中。main方法再将对应的变量的值赋给对象。

静态方法区在方法区内,用于存储静态方法,与类一起加载。

属性: 字段Field 成员变量

默认初始化:

  • 数字: 0 0.0
  • char : u0000
  • boolean:false
  • 引用 :null

三大特征

封装
  • 该露的露,该藏的藏
    • 我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
  • 封装(数据的隐藏)
    • 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。

记住这句话就够了:属性私有,get/set

封装的作用

  1. 提高程序的安全性
  2. 隐藏代码的实现细节
  3. 统一接口
  4. 系统可维护增加了
package com.oop.demo03;
//private  标识符:私有的
public class Student {
    private String name;
    private int age;
    private char sex;
   //提供一个可以操作这个属性的方法!
   //提供一些public的get set方法

    //get获得这个数据
public String getName(){
    return this.name;
}
    //set给这个数据设置值
public void setName(String name){
    this.name=name;
}
//alt+insert 快捷生成get/set方法
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
    if (age<=0||age>120){
        this.age=0;
    }else{
        this.age = age;
    }
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }
}

public void setAge(int age) {
if (age<=0||age>120){
    this.age=0;
}else{
    this.age = age;
}
}

public char getSex() {
    return sex;
}

public void setSex(char sex) {
    this.sex = sex;
}

}

package com.oop.demo03;

public class Text {
    public static void main(String[] args) {
        Student st1 = new Student();
        st1.setName("小明");
        st1.setAge(120);
        System.out.println(st1.getName()+"今年"+st1.getAge()+"岁");
    }
}

结果:

小明今年120
继承

继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
extends的意思是"扩展”。子类是父类的扩展。
JAVA中类只有单继承,没有多继承!

继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
继承关系的俩个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
子类和父类之间,从意义上讲应该具有"is a"的关系.
好处: 提高了代码的维护性和复用性

弊端: 使类与类之间产生了关系,类的耦合性增强,当父类发生变化,子类也必须发生变化,削弱了类的独立性。

继承中变量的访问特点
在子类方法中访问一个变量

  • 子类局部范围找

  • 子类成员范围找

  • 父类成员范围找

  • 如果都没有就报错(不考虑父亲的父亲…)

package com.oop.demo04;
//Person 人:父类
public class Person {
    //在java中所有的类,都默认直接或间接继承Object类 
    public void say(){
        System.out.println("说了一句话");
    }
}
package com.oop.demo04;
//学生类   人的 :派生类,子类
//子类继承了父类,就会拥有父类的全部方法
public class Student extends Person{

}
package com.oop;
import com.oop.demo04.Student;
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();
    }
}
说了一句话

object类 :在java中所有的类,都默认直接或间接继承Object类
super 注意点:

  1. super调用父类的构造方法,必须在构造方法的第一个。
  2. super 必须只能出现在子类的方法或者构造方法中!
  3. super和this 不能同时调用构造方法!

对比this

​ 代表的对象不同:

  • this:本身调用者这个对象

  • super :代表父类对象的应用

    前提:

  • this 没有继承也能使用

  • super: 只有在继承条件下才能使用

    构造方法:

  • this();本类的构造

  • super();父类的构造!

package com.oop.demo04;
//Person 人:父类
public class Person {
    //在java中所有的类,都默认直接或间接继承Object类
    //public
    //protected
    //default
    //private
    String name="dong";
    public void say(){
        System.out.println("说了一句话");
    }

}
package com.oop.demo04;
//学生类   是人 :派生类,子类
//子类继承了父类,就会拥有父类的全部方法
public class Student extends Person{
String name ="tian";
public void text1(String name){
    System.out.println(name);
    System.out.println(this.name);
    System.out.println(super.name);
}
}
package com.oop;

import com.oop.demo04.Student;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();
        student.text1("yu");
    }
}

结果:

说了一句话
yu
tian
dong
方法重写

需要有继承关系,子类重写父类的方法

  1. 方法名必须相同
  2. 参数列表必须相同
  3. 修饰符:范围可以扩大但不能缩小:public>protect>default>private
  4. 抛出的异常:范围,可以缩小但不能扩大:ClassNotFoundException–> Exception(大)

重写,子类的方法和父类必须一致,方法体不同!

为什么要重写:

父类的功能,子类不一定需要或者不一定满足!

快捷键:Alt +Insert :override

package com.oop.demo05;
//子类
public class B extends A{
    public  void test(){
        System.out.println("c==>text()");
    }
}
package com.oop.demo05;
//父类
public class A {
    public  void test(){
        System.out.println("A==>text()");
    }
}
package com.oop;

import com.oop.demo05.A;
import com.oop.demo05.B;

public class Application {
    public static void main(String[] args) {
        //方法的调用只和左边。定义的数据类型有关
        B b = new B();//左边引用类型,右面实际类型
        b.test();//B
       //父类的引用指向了子类
        A a =new B();
        a.test();
    }
}
c==>text()
c==>text()

无法重写的方法:

  1. static 静态方法,属于类,它不属于实例
  2. final 常量
  3. private 私有方法
super内存分析

1.main方法加载到栈内存,实例化子类
在这里插入图片描述
2.new 在堆内存申请地址,并初始化子类成员变量。
在这里插入图片描述
3.调用子类的无参构造方法,构造方法被加载到栈内存中

在这里插入图片描述
4.执行子类的无参构造会默认先执行父类的无参构造
在这里插入图片描述

在这里插入图片描述
5.初始化父类的成员变量并存储到堆内存的super空间中

在这里插入图片描述

6.执行父类的无参构造,构造方法被加载到栈内存中,将结果输出到控制台

在这里插入图片描述

父类构造方法执行完后会从栈内存消失

在这里插入图片描述

7.返回子类无参构造方法继续执行,将结果输出到控制台
在这里插入图片描述

执行完毕后,子类构造方法会从栈内存消失

在这里插入图片描述

8.继续执行main方法
在这里插入图片描述

将show方法加载到栈内存,执行show方法,执行完毕后从栈内存消失。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.继续执行main方法,先查找子类,子类不存在该方法,继续查找父类,父类存在该方法,控制台输出该方法执行结果。

在这里插入图片描述

10.main方法执行完毕,从栈内存消失,结束程序。在这里插入图片描述

多态

即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
多态存在的条件

  • 有继承关系
  • 子类重写父类方法
  • 父类引用指向子类对象

注意:

  • 多态是方法的多态,属性没有多态性。
  • 父类和子类,有联系 类型转换异常 ClassCastException!
  • 存在条件:继承关系,方法需要重写,父类引用指向子类对象! Father f1 = new Son();
package com.oop.demo06;

public class Person {
    public void run(){
        System.out.println("run");

    }
    public void eat(){
        System.out.println("吃东西");
    }
}
package com.oop.demo06;

public class Student extends Person{
    @Override
    public void run() {
        System.out.println("son");
    }
}
package com.oop;

import com.oop.demo06.Person;
import com.oop.demo06.Student;

public class Application {
    public static void main(String[] args) {
     //一个对象的实际类型是确定的
        //new Student();
        //new Person();
        //可以指向的引用类型就不确定了:父类的引用指向子类

        //子类能调用的方法都是自己的或者继承父类的
        Student s1 = new Student();
        //父类型可以指向子类但是不能调用子类独有的方法
        Person  s2 = new Student();
        Object  s3 = new Student();
          //对象能执行那些方法,主要看对象左边的类型,和右边关系不大
        s1.run();//子类重写父类的方法,执行子类的方法
        s2.run();
        s1.eat();
        s2.eat();


    }
}

结果:

son
son
吃东西
吃东西
instanceof 关键字

​ 判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例,即它左边的对象是否是它右边的类的实例,该运算符返回boolean类型的数据。

package com.oop;

import com.oop.demo06.Person;
import com.oop.demo06.Student;
import com.oop.demo06.Teacher;
//Person 父类  
//Student 、Teacher 子类
public class Application {
    public static void main(String[] args) {
        Object object = new Student();

        System.out.println(object instanceof Student);
        System.out.println(object instanceof Person);
        System.out.println(object instanceof Object);
        System.out.println(object instanceof String);
        System.out.println(object instanceof Teacher);
        System.out.println("=======================");
        Person person = new Student();
        System.out.println(person instanceof Student);
        System.out.println(person instanceof Person);
        System.out.println(person instanceof Object);
        System.out.println(person instanceof Teacher);
        // System.out.println(person instanceof String); 编译出错
        System.out.println("=======================");
        Student student = new Student();
        System.out.println(student instanceof Student);
        System.out.println(student instanceof Person);
        System.out.println(student instanceof Object);
        // System.out.println(student instanceof String);  编译出错
        // System.out.println(student instanceof Teacher); 编译出错

    }
}
true
true
true
false
false
=======================
true
true
true
false
=======================
true
true
true
类型转换
  1. 父类引用指向子类的对象

  2. 子类转换为父类,向上转换:直接转换

  3. 父类转换为子类,向下转换:强制转换

  4. 方便方法的调用,减少重复的代码!

package com.oop;

import com.oop.demo06.Person;
import com.oop.demo06.Student;
import com.oop.demo06.Teacher;

public class Application {
    public static void main(String[] args) {
        Person student =new Student();
        //强制转换
        //第一种方式
        Student stu2=(Student) student;
        stu2.run();
        //第二种方式
        ((Student)student).run();
    }
}
//子类转换为父类,可能丢失自己本来的一些方法!
run
run

抽象类

abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。
抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。
抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。

package com.oop.demo08;
//abstract 抽象类
public abstract class Action {
    //约束 有人帮我们实现
    //abstract 抽象方法,只有方法名字,没有方法的实现!
    public abstract void doSomething();
}
package com.oop.demo08;
//抽象类的所有方法,继承了它的子类,都必须要实现它的方法
public class A extends Action{
    @Override
    public void doSomething() {

    }
}
//1.不能new这个抽象类,只能靠子类区实现它:约束
//2.抽象类中可以写普通的方法
//3.抽象方法必须写在抽象类中

接口

普通类: 只有具体实现
抽象类: 具体实现和规范(抽象方法)都有!
接口: 只有规范!自己无法写方法。

接口就是规范,定义的是一组规则,体现了现实世界中“如果你…则必须能…的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人:如果你是坏人,则必须欺负好人。
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。

接口的精髓,是对对象的抽象,最能体现这一点的就是 接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如C++. java. c#等)。就是因为设计模式所研究的,实际上就是如何合理的去抽象。

声明类的关键字是class声明接口的关键字是interface

package com.oop.demo09;
//interface 定义的关键字,接口都需要有实现类
public interface UserService {
    //接口中的所有定义其实都是抽象的 public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
    //接口中定义的属性都为常量 public static final
    int age=99;//一般不用

}
package com.oop.demo09;

public interface TimeService {
    void timer();
}
package com.oop.demo09;
//类 可以实现接口 implements 接口
//实现了接口的类,就需要重写接口中的方法
//利用接口实现伪多继承
public class UserServiceImpl implements UserService,TimeService {
    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void timer() {

    }
}

作用:

  1. 约束

  2. 定义一些方法,让不同的人实现~

  3. public abstract 方法默认修饰符

  4. public static final 属性默认修饰符

  5. 接口不能被实例化,接口中没有构造方法

  6. implements可以实现多个接口

  7. 必须要重写接口中的方法

内部类

内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。

1.成员内部类

package com.oop.demo10;

public class Outer {
    private int id=10;
    public void out(){
        System.out.println("这是外部类的方法");
    }
   public  class Inner{
        public void in(){
            System.out.println("这是一个内部类");
        }
        //获取外部类的私有属性
       public  void getID(){
           System.out.println(id);
       }
    }

}

2.静态内部类

package com.oop.demo10;

public class Outer {
    private int id=10;
    public void out(){
        System.out.println("这是外部类的方法");
    }
   public static class Inner{
        public void in(){
            System.out.println("这是一个静态内部类");
        }
        //获取外部类的私有属性
       public  void getID(){
           System.out.println(id);
       }
    }

}

3.局部内部类

package com.oop.demo10;

public class Outer {
   //局部内部类
    public void method(){
        class  Inner{
         public void in(){
             
         }
        }
    }
}
//一个类中可以有多个class类,但只能有一个public class 类
class A{

}

4.匿名内部类

package com.oop.demo10;

public class Test {
    public static void main(String[] args) {
        //没有名字初始化类,不用将实例保存到变量中
        new Apple().eat();
    }
}
class Apple{
    public void eat(){
        System.out.println("1");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值