前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java面向对象三大特性「建议收藏」

java面向对象三大特性「建议收藏」

作者头像
全栈程序员站长
发布2022-09-08 11:01:56
6980
发布2022-09-08 11:01:56
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

一、面向对象的概念

面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物使用对象的关系来描述事物之间的联系,这种思想就是面向对象。

提到面向对象,自然会想到面向过程,面向过程就是分析解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候一个一个依次调用就可以了。面向对象则是把解决的问题按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。当然,一个应用程序会包含多个对象,通过多个对象的相互配合来实现应用程序的功能,这样当应用程序功能发生变动时,只需要修改个别的对象就可以了,从而使代码更容易得到维护。

二、面向对象的特点

面向对象的特点主要可以概括为封装性、继承性和多态性,接下来针对这三种特性进行简单介绍。

1、封装性

封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节,这就是封装思想。例如,用户使用电脑,只需要使用手指敲键盘就可以了无须知道电脑内部是如何工作的,即使用户可能碰巧知道电脑的工作原理,但在使用时,并不完全依赖电脑工作原理这些细节。

2、继承性

继承性主要描述的是类与类之间的关系,通过继承,可以在无须重新编写原有类的情况下,对原有类的功能进行扩展。例如,有一个汽车的类,该类中描述了汽车的普通特性和功能,而轿车的类中不仅应该包含汽车的特性和功能,还应该增加轿车特有的功能,这时,可以让轿车类继承汽车类,在轿车类中单独添加轿车特性的方法就可以了。继承性不仅增强了代码复用性,提高了开发效率,而且为程序的修改补充提供了便利。

3、多态性

多态性指的是在程序中允许出现重名现象,它指在一个类中定义的属性和方法被其他类继承后,它们可以具有不同的数据类型或表现出不同的行为,这使得同一个属性和方法在不同的类中具有不同的语义。

封装

1、封装的优点:

  1. 良好的封装能够减少耦合。
  2. 类内部的结构可以自由修改。
  3. 可以对成员变量进行更精确的控制。
  4. 隐藏信息,实现细节。

2、封装的实现步骤

1、使用 private 关键字来修饰成员变量。 2、对需要访问的成员变量,提供公共的访问方式,也就是定义对应的 getXxx 方法 、setXxx 方法。

注意:对封装的属性不一定要通过get/set方法,其他方法也可以对封装的属性进行操作。当然最好使用get/set方法,比较标准。

访问修饰符:

从表格可以看出从上到下封装性越来越差。

this关键字

代码语言:javascript
复制
1)this代表什么?:代表是当前类对象(谁调用这个方法,this就是指谁)
2)在方法中调用属性加this和不加this的区别?
        this.属性:一定指定的属性
        变量名(属性名相同):先查看此方法中是否有变量或参数同名,该变量指的就是
        该变量或参数,如果方法中不存在同名的参数和变量,则指的是同名的属性,否则报错

代码如下:

代码语言:javascript
复制
public class Dog{ 
   
    public  Dog() { 
   
        System.out.println("狗出生了---顺产");
    }
    //自己添加的构造方法
    public   Dog(String name,String strain) { 
   
        this.name = name;
        this.strain = strain;
        System.out.println("狗出生了...---难产.");
    }
    
    public Dog(String a,int b) { 
   
       System.out.println("狗出生了----剖腹产");
    }
    public Dog(int b,String a) { 
   
        System.out.println("狗出生了----流产出来了");
    }
    
    String name = "无名氏"; // 昵称,默认值是"无名氏"
    int health = 100; // 健康值,,默认值是100
    int love = 0; // 亲密度
    String strain = "哈士奇"; // 品种
    /** * 输出狗狗的信息。 */
    public void print() { 
   
        System.out.println("宠物的自我介绍:\n我的名字叫" + this.name +
                ",健康值是" + this.health + ",和主人的亲密度是"
                + this.love + ",我是一只 " + this.strain + "。");
    }
}

Java 中的内部类

内部类( Inner Class )就是定义在另外一个类里面的类。与之对应,包含内部类的类被称为外部类。

内部类可分为以下几种:

  • 成员内部类
  • 静态内部类
  • 方法内部类
  • 匿名内部类

作用:

  1. 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
  2. 内部类的方法可以直接访问外部类的所有数据,包括私有的数据。
  3. 内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便。

继承

概念: 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

在现实生活中,继承一般指的是子女继承父辈的财产。在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系

继承是类与类的一种关系,是一种“is a”的关系。如图

兔子和羊属于食草动物类,狮子和豹属于食肉动物类。 食草动物和食肉动物又是属于动物类。 虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。 注意:java中的继承是单继承,即一个类只有一个父类。

继承的格式

代码语言:javascript
复制
class 父类 { 
   
}
 
class 子类 extends 父类 { 
   
}

补充:Java中的继承只能单继承,但是可以通过内部类继承其他类来实现多继承。 如:

代码语言:javascript
复制
public class Son extends Father{ 
   
public void go () { 
   
System.out.println("son go");
}
public void eat () { 
   
System.out.println("son eat");
}
public void sleep() { 
   
System.out.println("zzzzzz");
}
public void cook() { 
   
//匿名内部类实现的多继承
new Mother().cook();
//内部类继承第二个父类来实现多继承
Mom mom = new Mom();
mom.cook();
}
private class Mom extends Mother { 
   
@Override
public void cook() { 
   
System.out.println("mom cook");
}
}
}

继承的特性:

  • 子类拥有父类非 private 的属性、方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

super 关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。 如:

代码语言:javascript
复制
class Animal { 
   
  void eat() { 
   
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal { 
   
  void eat() { 
   
    System.out.println("dog : eat");
  }
  void eatTest() { 
   
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}
 
public class Test { 
   
  public static void main(String[] args) { 
   
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

==========
结果:
animal : eat
dog : eat
animal : eat

final关键字

final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:

代码语言:javascript
复制
声明类:

final class 类名 { 
   //类体}
声明方法:

修饰符(public/private/default/protected) final 返回值类型 方法名(){ 
   //方法体}

注:实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final

继承的初始化顺序

1、初始化父类再初始化子类

2、先执行初始化对象中属性,再执行构造方法中的初始化。

基于上面两点,我们就知道实例化一个子类,java程序的执行顺序是:

父类对象属性初始化—->父类对象构造方法—->子类对象属性初始化—>子类对象构造方法

多态

面向对象的多态性,即“一个接口,多个方法”。多态性体现在父类中定义的属性和方法被子类继承后,可以具有不同的属性或表现方式。多态性允许一个接口被多个同类使用,弥补了单继承的不足。

使用多态的好处:

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性

多态存在的三必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象:Parent p = new Child();

java中多态主要表现在以下两方面

1、引用多态

父类的引用可以指向本类的对象; 父类的引用可以指向子类的对象

这两句话是什么意思呢,让我们用代码来体验一下,首先我们创建一个父类Animal和一个子类Dog,在主函数里如下所示:

注意:我们不能使用一个子类的引用来指向父类的对象,如:

为什么子类的引用不能用来指向父类的对象呢?就以上面的例子来说,我们能说“狗是一种动物”,但是不能说“动物是一种狗”,狗和动物是父类和子类的继承关系,它们的从属是不能颠倒的。当父类的引用指向子类的对象时,该对象将只是看成一种特殊的父类(里面有重写的方法和属性),反之,一个子类的引用来指向父类的对象是不可行的!!

2、方法多态

根据上述创建的两个对象:本类对象和子类对象,同样都是父类的引用,当我们指向不同的对象时,它们调用的方法也是多态的。

创建本类对象时,调用的方法为本类方法;

创建子类对象时,调用的方法为子类重写的方法或者继承的方法;

使用多态的时候要注意:如果我们在子类中编写一个独有的方法(没有继承父类的方法),此时就不能通过父类的引用创建的子类对象来调用该方法!!!

注意: 继承是多态的基础。

引用类型转换

1.向上类型转换(隐式/自动类型转换),是小类型转换到大类型

就以上述的父类Animal和一个子类Dog来说明,当父类的引用可以指向子类的对象时,就是向上类型转换。如:

2. 向下类型转换(强制类型转换),是大类型转换到小类型(有风险,可能出现数据溢出)。

将上述代码再加上一行,我们再次将父类转换为子类引用,那么会出现错误,编译器不允许我们直接这么做,虽然我们知道这个父类引用指向的就是子类对象,但是编译器认为这种转换是存在风险的。如:

 那么我们该怎么解决这个问题呢,我们可以在animal前加上(Dog)来强制类型转换。如:

 但是如果父类引用没有指向该子类的对象,则不能向下类型转换,虽然编译器不会报错,但是运行的时候程序会出错,如:

还有一种情况是父类的引用指向其他子类的对象,则不能通过强制转为该子类的对象。如:

因为我们在编译的时候进行了强制类型转换,编译时的类型是我们强制转换的类型,所以编译器不会报错,而当我们运行的时候,程序给animal开辟的是Dog类型的内存空间,这与Cat类型内存空间不匹配,所以无法正常转换。这两种情况出错的本质是一样的,所以我们在使用强制类型转换的时候要特别注意这两种错误

来看一个例子:

代码语言:javascript
复制
abstract class Animal { 
     
    abstract void eat();  
}  
  
class Cat extends Animal { 
     
    public void eat() { 
     
        System.out.println("吃鱼");  
    }  
    public void work() { 
     
        System.out.println("抓老鼠");  
    }  
}  
  
class Dog extends Animal { 
     
    public void eat() { 
     
        System.out.println("吃骨头");  
    }  
    public void work() { 
     
        System.out.println("看家");  
    }  
}
==============================================

public class Test { 
   
    public static void main(String[] args) { 
   
      show(new Cat());  // 以 Cat 对象调用 show 方法
      show(new Dog());  // 以 Dog 对象调用 show 方法
                
      Animal a = new Cat();  // 向上转型 
      a.eat();               // 调用的是 Cat 的 eat
      Cat c = (Cat)a;        // 向下转型 
      c.work();        // 调用的是 Cat 的 work
  }  
            
    public static void show(Animal a)  { 
   
      a.eat();  
        // 类型判断
        if (a instanceof Cat)  { 
     // 猫做的事情 
            Cat c = (Cat)a;  
            c.work();  
        } else if (a instanceof Dog) { 
    // 狗做的事情 
            Dog c = (Dog)a;  
            c.work();  
        }  
    }  
}

输出结果:
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠

instanceof运算符,用来解决引用对象的类型,避免类型转换的安全性问题。

instanceof是Java的一个二元操作符,和==,>,<是同一类的。由于它是由字母组成的,所以也是Java的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据。

代码语言:javascript
复制
 public void play(Aninmos aninmos){ 
   
        if (aninmos instanceof Dog) { 
   
        Dog dog = (Dog) aninmos;
        dog.jie();
    }else if (aninmos instanceof Penguin) { 
   
        Penguin pgn = (Penguin) aninmos;
        pgn.swimming();
    }

最后呢 欢迎留言评论

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157127.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 封装
  • 继承
  • 多态
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档