面向对象知识总结

目录

 

一、Java的面向对象编程

1、类和对象

2、类和对象的关系

3、面向对象的特征

4、构造器(Construct):

二、Java的面向对象的特征

1、封装

2、访问修饰符的权限

3、static关键字

4、继承

4.1、概念

4.2、继承的语法

4.3、重写

三、抽象类

1、定义

2、抽象类的特点

四、接口

1、定义

2、接口语法

3、接口中的成员组成部分 特点

五、多态

1、 定义

2、实现多态的前提

3、多态的对象转型

4、在多态环境型,方法和属性的调用规则


一、Java的面向对象编程

Java作为面向对象的语言,关于面向对象语言的核心概念

1、类和对象

类: 一类事物的抽象的模板,在现实世界中 类就是任意一类事物 ,在程序中类就是一个描述这类事物的类文件。

对象: 在这一类事物中,具体的某一个个体就是对象 ,在程序中对象就是new出来的有内存空间

2、类和对象的关系

类和对象的关系: 类是抽象的而对象是具体的, 对象是由类创建的实例(new出来的)

类的组成(人类):

类名: 给某一类事物取个名字: People

静态的特征称为属性: 姓名,年龄,身高,体重 (定义变量的语法)

动态的行为称为方法: 吃饭,睡觉,打豆豆 (方法的定义依然满足之前所学)

类的实现:

在一个类文件(People)中,定义属性和方法

对象的实现:

通过类名创建这个类的对象。

注意 类名不能直接访问 它里面的属性和方法的,必须由类的对象访问

package com.j2008.init;

/**
 * ClassName: People
 * Description:
 * date: 2020/10/7 11:06
 *  创建一个People类  ,并定义这个类的属性(静态的特征)
 *  和 这个类的方法 (动态的行为)
 *
 * @author wuyafeng
 * @version 1.0   softeem.com
 */
public class People {
    // 定义姓名属性   数据类型 和属性名 = [初始值]
    String name="张三";
    // 定义性别属性
    String sex="男";
    // 定义身高属性
    double height =1.75;
    // 定义体重属性
    double weight = 140;

    /**
     * 定义吃饭的行为(方法)
     */
    public void eat(){
        System.out.println("正在吃饭");
    }

    /**
     * 定义睡觉方法
     */
    public void sleep(){
        System.out.println("正在睡觉");
    }

    /**
     * 定义打豆豆方法
     */
    public void playGame(){
        System.out.println("正在打豆豆");
    }
    // 计算两个数相加
    public int add(int a, int b){
        return a+b;
    }


}
public static void main(String[] args) {
         //  不同通过People直接访问它 需要创建类的实例,也就是对象
        //  创建对象的过程称为类的实例化
        // 语法: 类名  对象名   =  new  类名() ;
        People people = new People();
        // 这时候才可以通过对象名 访问这个对象具有的属性 和 方法
         // 对象名.属性名
        // 对象名.方法名([实参])
        System.out.println("这个对象的属性name :"+ people.name);
        System.out.println("这个对象的属性 sex :" + people.sex);
        System.out.println("这个对象的属性 weight :"+ people.weight);
        System.out.println("这个对象的属性height:"+ people.height);
        // 调用对象的访问
        people.eat();
        people.sleep();
        people.playGame();
       int result =  people.add(2,4);
        System.out.println("这个对象还可以计算 结果:"+result);

    }

 

3、面向对象的特征

面向对象的三大特征: 封装、继承、多态

封装: 将类中成员属性 私有化,并提供公有的访问属性的方法。 为了最大程度保护类中属性的隐蔽性(不被其他对象改变。)

继承: 用于定义类与类的关系的方式 ,一个类可以继承一个类。

多态: 在继承关系中,一个类的对象可能呈现不同的状态。

 

 

4、构造器(Construct):

定义: 在创建对象时被自动调用的特殊方法,也称为构造方法。 在一个类中除了包含属性,方法以外,还可以包含 构造器(构造方法)

每一个类都自带一个无参构造器,也可以在这个类中定义多个构造器,多个构造器之间称为“构造器重载”

语法:

 访问修饰符 类名([参数列表]){
      
  } 
//例如

public	class	Student{
    
     //无参构造器
    public	Student	(){
        System.out.println("这是一个无参构造器");
    }
}

构造器的作用:

1、用于创建对象自动调用 ,并可以给对象的属性赋初始值

public	class	Student{
         String	name;//对象的属性
       //有参构造器
       public	Student	(String	name1){
            name=name1;
      }
         //注意一个类中如果存在有参构造器,那么它的无参构造器被覆盖。
  }
创建对象:
   Student	stu	=	new	Student("张三");
     //这里会自动调用有参构造器	并将“张三”赋值给name1,由于自动执行以上构造器,将name1的值赋值给name,这个name就是对象的属性
     System.out.print(stu.name);//张三

类与类的关联关系 :

如果在一个类中引用另一个类,那么这两个类属于关联关系,

例如一个小明同学养了一条狗,如何通过面向对象的方式定义小明同学用于狗的关系

思路: 定义一个People类,其中name属性 ,

定义一个Dog类 包含dogName ,dogColor

将People类与Dog类关联关系 ,在People类中 创建Dog类的引用

public class People {
    String name;
     // 在People类中 建立 People对象与Dog对象的关系
    Dog dog;

    public People(String name){
        this.name = name;  // 将形参name 赋值给 当前对象的成员属性name
    }

}
public class Dog {
    // 由于以下属性 属于狗的特征,所以必须放在Dog类中,而不能放在People类
    String dogName;
    String dogColor;

    /**
     * 创建Dog对象时 初始化狗的基本属性
     * @param dogName
     * @param dogColor
     */
    public Dog(String dogName ,String dogColor){
        this.dogName = dogName;
        this.dogColor = dogColor;
    }
}
public static void main(String[] args) {
        // 先创建一个小明同学
        People people = new People("小明同学");
        System.out.println("people.dog:"+people.dog);
        // 再创建一个 Dog对象
        Dog dog = new Dog("拉布拉多","灰白");
        System.out.println("dog:"+dog);
         、 //设置dog和people对象的关系
        people.dog = dog;
        System.out.println("people.dog:" +dog);

    }

二、Java的面向对象的特征

1、封装

为了提高类的隐蔽性,对类实现的细节隐藏,提供外部访问的接口即可,提高代码的可扩展性

生活中的封装: 例如笔记本 的内部结构统一封装了,一般人使用笔记本时不需要了解笔记本的结构,而是直接开机关机使用。

对代码的封装包括两层意思:

1、对类的成员属性的封装 :

将属性私有化(private),提供对属性的访问给属性添加公用的getter和setter方法

2、对代码的封装:

为了提高代码的复用性,尽量使用方法加参数传递对代码进行封装,并使该方法公有(public)

public class People {
    private String pname;
    private int age;
    private String sex;
    // 提供 getter 和 setter
    public String getPname(){
        return pname;
    }
    public void setPname(String pname){
        this.pname=pname;
    }

    public int getAge(){
        return age;
    }
    public void setAge(int age){
        // 对成员属性的隐蔽性 可以防止随意对属性更改
        if(age>100 || age<0){
            System.out.println("赋值的年龄不合法");
            return;
        }
        this.age = age;
    }

    public String getSex(){
        return sex;
    }
    public void setSex(String sex){
        this.sex= sex;
    }


    // 通常为了方便给属性赋值,会提供有参构造
    public People(String pname ,int age,String sex){
        this.pname = pname;
        this.age = age;
        this.sex = sex;
    }
    public People(){

    }
 }

对于boolean类型的属性,需要使用isXxx返回属性的值。

封装的优点:

1、良好的封装可以减少类的耦合性(类与类的关联)

2、对类中封装的代码可以自由修改,而不会影响其他类

3、最大程度提高类中属性的隐蔽性 和对属性的控制

2、访问修饰符的权限

用于修饰类,属性,方法的关键字都称为访问修饰符

  1. 1、public :公共的

可被同一个项目的所有类方法(项目可见性)

  1. 2、protected :受保护

可以被自身的类访问

可以被同包下的其他类访问

对于不同包的,存在父子关系的子类可以访问

  1. 3、默认的

可以被自身类访问

可以被同包下的其他类访问

  1. 4、private: 私有的

只能被自身类访问

3、static关键字

static表示“静态” ,它可以修饰 属性,方法,代码块 , 在一个类中除了可以定义成员属性、成员方法和构造器以外,还可以定义静态的部分(静态属性,静态方法,静态代码块)

static 修饰属性:称为 静态属性或类的属性

static修饰方法:称为静态方法或类的方法

static修饰的语句块: 称为静态代码块

static修饰的组件不需要通过对象访问,而是直接通过类名访问,在类一加载时会给static修饰的属性和方法分配内存区,这个内存分布在 静态内存区中。后续所有对象操作的是同一个内存区

案例一:

public class Student {
    //  成员属性
    String name;
    // 静态属性  通常static写在public的后面
    static  int age=20;

    // 静态代码块
    static{
        System.out.println("这是静态代码块,在类一加载时,就会被执行,且只执行一次");
    }

    //成员方法  : 既可以访问 成员属性,也可以访问静态属性
    public void getInfo(){
        System.out.println("姓名:"+name +" 年龄:" +age);
    }
    // 静态方法 : 只能访问静态属性,不能访问成员属性(非静态属性
    //   这是为什么? 由于成员属性的存在需要依赖对象 ,
    // 静态属性和静态方法在创建对象之前就必须初始化并分配内存
    public static void getStaticInfo(){
       // System.out.println("姓名:"+name);  成员属性不能被访问
        System.out.println("静态属性:"+age);
    }


    public Student(){
        System.out.println("无参构造器");
    }

    // 构造代码块
    {
        System.out.println("构造代码块");
    }


    public static void main(String[] args) {
        System.out.println("访问静态属性:"+Student.age);
        // 访问静态方法
        Student.getStaticInfo();




    }
 // 类的组件执行顺序
        // 类编译成.class文件被JVM的类加载器加载-》
        // 从上往下初始化static修饰的组件
        // (静态属性,静态代码块,静态方法,其中静态方法调用才执行,静态属性和静态代码块直接分配内存)-》
        //  --》构造代码块-》执行构造器  -》初始化成员属性,成员方法
        Student stu1 = new Student();
        stu1.name="张三";
        // 静态属性可以通过类名访问,也可以通过对象名访问
        stu1.age=21;
        System.out.println(stu1);

        Student stu2 = new Student();
        stu2.name="王麻子";
        stu2.age=22;
        System.out.println(stu2);

        System.out.println(stu1.name);
        System.out.println(stu1.age); //   22

        System.out.println(stu2.name); //王麻子
        System.out.println(stu2.age); // 22

        System.out.println(Student.age);//  22

    }

案例二: 静态的变量 在同一个内存中

public class People {
    double height;
    static int score;
    static{
       score++; // 1
    }
   public void setScore(){
       score++; //81  86
   }
   public static void setScore2(){
        score++;
   }

    public static void main(String[] args) {
         People p1 = new People();
         p1.score=80;//静态属性
         p1.setScore();
         People.score=85;
         p1.height= 1.75;
         People p2 = new People();
         p2.setScore(); //86
         p2.height= 1.80;

        System.out.println(p1.score); // 86
        System.out.println(p1.height); // 1.75

        System.out.println(p2.score);//86
        System.out.println(p2.height);// 1.80

    }

}

案例三: 构造代码块和静态代码块 的执行顺序

package com.j2008.statics;

/**
 * ClassName: UserInfo
 * Description:
 * date: 2020/10/8 11:53
 *
 * @author wuyafeng
 * @version 1.0   softeem.com
 */
public class UserInfo {
    //  关于静态的组件 从上往下执行

    // 静态属性  需要先初始化 ,需要new一个对象
    static UserInfo u = new UserInfo(); // 先执行构造代码块 在执行构造器
    static{
        System.out.println("这是静态代码块,只执行一次");
    }

    public UserInfo(){
        System.out.println("这是无参构造器");
    }
    {
        System.out.println("构造代码块");
    }

    public static void main(String[] args) {
         // 结果
        UserInfo u = new UserInfo();
    }


}

4、继承

4.1、概念

当多个类中都存在相同的属性和行为时,可以将这些共有的属性和行为定义到一个新的类中,让其他类服用这个新类的属性和行为,这种关系就是继承关系

当满足 XXX是 一个XXX的时候,也是继承关系,例如 苹果是一种水果,其中水果就是父类,苹果就是子类, 水果有多种水果,而苹果只是水果的一种,所以苹果继承水果

其中 被继承的类是 父类(超类,基类),继承父类的类就是子类(新类,派生类)

4.2、继承的语法

2.1 子类继承父类,子类拥有父类的哪些属性和方法?

可访问: 子类拥有父类的共有的属性和方法, 同包下面的属性和方法,不同包下的受保护的也可以访问

不可访问: 其中子类不能继承 父类的私有的属性和方法、不同包的默认属性和方法 ,不能继承父类的构造器

 

2.2 子类继承父类,子类如何访问父类的属性和方法

属性: 子类通过super 关键字访问父类的属性 ,子类通过this关键字访问自己的属性

方法:子类通过super挂件自方法父类的方法, 子类通过this关键字访问自己的方法

注意: 这里的this和super可以省略,省略后子类通过“就近原则”访问属性和方法(子类中存在就访问子类的,子类中不存在,就访问父类的。)

super.属性

super.方法(参数)

构造器:子类通过super([参数]) 调用父类的构造器, 子类通过this([参数])调用 自己类的其他构造器,其中 super(参数[]) 必须写在子类构造器的第一行

注意: 子类构造器中默认调用父类的无参构造器

2.3 Java中只能是单继承,一个类只能有一个直接父类的父类,可实现多层次继承

子类 -》 父类 -》 父类的父类

pupil -> Student-》 People

创建子类对象时,优先创建父类对象,再创子类对象, 执行顺序 最上层父类的构造器 -》 父类构造器 -》子类构造器。

扩展问题:当一个类中存在static元素时,它们的执行顺序是如何?

顺序: 最上层父类的静态块 - 》 父类的静态块-》 子类的静态块- 》最上层 父类的构造块和构造方法

-》父类的构造块和构造方法- 》 子类的构造块和构造方法

 

4.3、重写

子类可以继承父类的方法,但是当父类的方法不能满足子类的需要时,子类可以重写父类的方法

重写的必要条件:

1、两个方法名必须相同,且存在不同类中(父子关系的类)

2、子类重写的父类的方法,其方法的参数和返回值必须完全一样,方法的具体实现可不一样

3、访问修饰符必须大于或等于父类的修饰符

 

注意: 子类的对象 调用父类方法时,如果子类重写了父类的方法,则执行子类的方法,没有重写执行父类的方法。

面试题:

说一下方法的重写与重载的区别?

1、重写存在于父子关系中的不同类,重载存在同类中

2、重写必须满足 方法名相同,且参数相同,返回值相同 ,重载满足方法名相同,参数不同,与返回值无关。

3、重写的访问修饰符必须 子类大于等于父类, 重载没有要求

三、抽象类

1、定义

在已有类的基础上,由于特殊情况将该类设置为抽象的,这个类就是抽象类

什么情况下需要定义抽象类?

1、当这个类不需要创建具体的实例时,可将类定义为抽象的

2、当这个类中存在没有实现的方式时(没有方法体的方法),可以将这个类定义抽象的

2、抽象类的特点

2.1 抽象类 不能实例化(不能new) ,通常抽象被当作父类使用

2.2 抽象类中 可以有抽象方法( 没有方法体的方法) 也可以有普通方法

2.3 抽象类被当作父类时,它的子类必须重写父类的抽象方法

public abstract class Fruit {
    private String color;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    // 水果的甜度  由于不知道是什么水果,所以说过的甜度未知,可以定义为抽象方法
    // 抽象方法
    public abstract void getSweet();

}
public  class Apple extends  Fruit {

    // 子类重写(实现)父类的抽象方法
    @Override
    public void getSweet() {
        System.out.println("这个水果有点甜");
    }
}
public class Lemon extends  Fruit {

    @Override
    public void getSweet() {
        System.out.println("这个水果有点酸,想想都觉得酸");
    }
}
public static void main(String[] args) {
        // 抽象类不能实例化
      //  Fruit fruit = new Fruit();
        // 创建子类对象
        Apple apple = new Apple();
        apple.setColor("红色");
        apple.getSweet();
        System.out.println(apple.getColor());

        Lemon lemon = new Lemon();
        lemon.setColor("黄色");
        lemon.getSweet();
        System.out.println(lemon.getColor());


    }
}

面试题:

抽象方法和非抽象方法的区别

回答:

抽象方法没有方法体,需要使用abstract修饰, 只能写在抽象类中

非抽象方法就是普通方法(成员方法或静态方法) ,可以写在抽象类中或普通类中。

 

四、接口

1、定义

接口用于对某件事物的功能的声明,而没有实现具体功能 ,接口提供对软件开发的标准规范。

利用接口的“多实现”完成Java的单一继承

2、接口语法

  public interface 接口名{
        抽象方法定义
  }

一个类实现该接口,必须实现接口的所有方法

  public class 实现类名  implements 接口名{
       实现接口的所有方法
  }

接口的好处:

1、为了规范实现类的行为,让所有的方法都通过接口定义

2、为了提高代码的可扩展性

接口定义实现类的对象 和 实现类定义试下类的对象的区别?

接口定义实现类的对象只能调用接口中定义的方法, 实现类定义的对象既可以调用实现类的方法,也可以调用接口类的方法。

 

3、接口中的成员组成部分 特点

接口中定义的变量默认全部是 public static final 修饰的

接口中的静态方法可以直接调用。

接口中不能写构造器(因为接口不能实例化,不需要构造器)

接口中的方法全部都是 抽象方法, 在JDK8以后可以定义default的非抽象方法

案例1 : 一个类既可以继承一个类 也可以实现多个接口

 

  //定义一个门类 ,定义一个防盗门,它具有防盗的功能,如何防盗 (防盗功能中可以 拍照, 密码锁)
  // 门本 身有 开门,关门 功能

 

案例2: 一个类可以实现多个接口,中间用逗号分隔 (那么这个类要实现接口的所有方法)

/**
 *  程序员身份
 */
public interface Programer {
    public void takeMoney();
}
/**
 * 厨师
 */
public interface Cooker {
    /**
     * 做好吃
     */
    public void makeFood();
}
public interface Driver {
    // 功能
    public void driverCar();

    public void takeMoney();
}
public class People implements Programer ,Cooker ,Driver {

    private String name;
    public People (String name){
        this.name = name;
    }
    @Override
    public void makeFood() {
        System.out.println("做好吃的");
    }

    @Override
    public void driverCar() {
        System.out.println("开车的功能");
    }

    @Override
    public void takeMoney() {
        System.out.println("赚钱的功能");
    }
}
 public static void main(String[] args) {
         People people = new People("袁巍巍");
         people.takeMoney();
         people.makeFood();
         people.driverCar();
    }

案例3:一个接口可以继承 接口,或多个接口(接口可以多继承)

一个员工接口 一个程序员 (由于程序员是员工,所有程序员可以继承员工接口 )

一个人 是员工也是 程序员 (People 是员工 程序员 )

 

五、多态

1、 定义

同一种行为,具有多个不同的表现形式

2、实现多态的前提

  • 基于继承关系或基于实现关系的

  • 子类或实现类必须对方法进行重写(没有重写的方法 不具有多态行为)

  • 父类的引用指向子类对象( 接口的引用指向实现类的对象)

3、多态的对象转型

1、子类对象转父类对象时,称为向上转型是默认转换,自动转型

 Cat cat = new Cat();
           // 猫类 可以是一只动物     an4的本质还是 猫对象
          Animal an4 = cat;    // 子类对象转成父类对象 ,是自动转型
           cat.eat();
           an4.eat();

2、父类的引用转成子类对象,称为向下转型,向下转型需要强转 , 为了避免转换错误,需要先判断数据类型是否匹配

 // 创建一个动物类, 将动物类转成子类引用
           Animal an5 = new Cat();
          //  an5.catchMouse(); // 动物类型对象不能访问 它子类特有的方法
          if(an5 instanceof Cat) {
              Cat cat2 = (Cat) an5;
              cat2.eat();
              cat2.catchMouse();
          }
          if(an5 instanceof  Dog) {
              Dog dog2 = (Dog)an5;
          }else{
              System.out.println("不能转成dog");
          }

4、在多态环境型,方法和属性的调用规则

属性: 当子类和父类中存在相同属性时 ,以 对象的左边引用类型为依据,所谓“看左边”

方法: 以当前new出来的对象为依据,如果方法重写了,就调用子类方法,如果方法没有重写 调用父类方法

静态方法: 无论方法是否有重写, 都已对象左边的引用类型为依据。

public class Student extends  People  {
      int age =20;

    @Override
    public void showAge() {
        this.age++;
        System.out.println("年龄:"+this.age+" ----"+super.age);

    }
    // 重写的静态方法
    public static void  method1(){
        System.out.println("method1------------  重写后的 方法");
    }

}
public static void main(String[] args) {
      People p1 = new People();
      System.out.println(p1.age);// 18
       p1.showAge();  // 对象的本质people  调用people

       People p2 = new Student();
      System.out.println( p2.age);// 18
      p2.showAge(); // 本质student ,且重写了 调Student
      p2.sleep();  // 本质student  ,没重写,调用people

        Student p3 = (Student)p2;
     System.out.println( p3.age); // 20
        p3.showAge(); // 本质student ,且重写了 调Student

        People p4 = p3;
     System.out.println( p4.age); // 18   看左边
        p4.showAge(); // 本质student ,且重写了 调Student

}

结论:

18

年龄:18

18

年龄:21 ----18

睡觉方法。。。。。

21

年龄:22 ----18

18

年龄:23 ----18

 

public static void main(String[] args) {
      People p1 = new People();
      p1.method1();
      p1.method2();

      People p2 = new Student();
      p2.method1();
      p2.method2();

      Student p3 = (Student)p2;
      p3.method1();
      p3.method2();

}

结论:

method1------------

method2---------

method1------------

method2---------

method1------------ 重写后的 方法

method2---------

 

总结常见面试题:

1、抽象类与接口的区别

共同点:

它们都是抽象的,都不能实例化

区别:

1、抽象类是类 使用abstract修饰,接口使用interface定义

2、抽象类中可以包含抽象方法和普通方法, 接口中是纯粹的抽象类,都是抽象方法,除使用default定义以外

3、子类继承抽象类,必须实现抽象类的方法,或者自身变为抽象类

接口中是实现关系,实现类必须实现接口的所有方法,接口的变量是public static final

2、重载和重写的区别?

重写存在于父子关系中的不同类,重载存在同类中

重写必须满足 方法名相同,且参数相同,返回值相同 ,重载满足方法名相同,参数不同,与返回值无关。

重写的访问修饰符必须 子类大于等于父类, 重载没有要求

3、在java中如何实现多态(多态的前提条件)?

4、final的作用

final修饰变量 定义为常量

final 修饰方法 不能被重写

final 修饰类 则不能被其他子类继承

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值