加载中...
avatar
文章
42
标签
25
分类
21
首页
Java
Spring全家桶
  • Spring
  • SpringBoot
  • SpringCloud
JVM
源码
  • Mybatis
  • HashMap
归档
其他
  • 互联网电子书汇总
  • JAVA八股文指南
  • 历史
  • 相册
关于
Logo码农StormlingJava系列(二)| 面向对象
搜索
首页
Java
Spring全家桶
  • Spring
  • SpringBoot
  • SpringCloud
JVM
源码
  • Mybatis
  • HashMap
归档
其他
  • 互联网电子书汇总
  • JAVA八股文指南
  • 历史
  • 相册
关于

Java系列(二)| 面向对象

发表于2021-09-17|更新于2025-01-07|Java
|总字数:3.8k|阅读时长:11分钟|浏览量:

面向对象和面向过程的区别?

  • 面向过程 :面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的一次调用就可以。
  • 面向对象 :面向对象,把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事件在解决整个问题的过程所发生的行为。目的是为了写出通用的代码,加强代码的重用,屏蔽差异性。

用一个比喻:面向过程是编年体;面向对象是纪传体。

面向对象和面向过程的区别

面向对象有哪些特性

面向对象三大特征

  • 封装

    封装把⼀个对象的属性私有化,同时提供⼀些可以被外界访问的属性的⽅法。

  • 继承

    继承是使⽤已存在的类的定义作为基础创建新的类,新类的定义可以增加新的属性或新的方法,也可以继承父类的属性和方法。通过继承可以很方便地进行代码复用。

关于继承有以下三个要点:

  1. ⼦类拥有⽗类对象所有的属性和⽅法(包括私有属性和私有⽅法),但是⽗类中的私有属性和⽅法⼦类是⽆法访问,只是拥有。
  2. ⼦类可以拥有⾃⼰属性和⽅法,即⼦类可以对⽗类进⾏扩展。
  3. ⼦类可以⽤⾃⼰的⽅式实现⽗类的⽅法。
  • 多态

    所谓多态就是指程序中定义的引⽤变量所指向的具体类型和通过该引⽤变量发出的⽅法调⽤在编程时并不确定,⽽是在程序运⾏期间才确定,即⼀个引⽤变量到底会指向哪个类的实例对象,该引⽤变量发出的⽅法调⽤到底是哪个类中实现的⽅法,必须在由程序运⾏期间才能决定。

    在 Java 中有两种形式可以实现多态:继承(多个⼦类对同⼀⽅法的重写)和接⼝(实现接⼝并覆盖接⼝中同⼀⽅法)。

重载(overload)和重写(override)的区别?

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。

  • 重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;
  • 重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。

方法重载的规则:

  1. 方法名一致,参数列表中参数的顺序,类型,个数不同。
  2. 重载与方法的返回值无关,存在于父类和子类,同类中。
  3. 可以抛出不同的异常,可以有不同修饰符。

访问修饰符 public、private、protected、以及不写(默认)时的区别?

Java 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

  • default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。可以修饰在类、接口、变量、方法。
  • private : 在同一类内可见。可以修饰变量、方法。注意:不能修饰类(外部类)
  • public : 对所有类可见。可以修饰类、接口、变量、方法
  • protected : 对同一包内的类和所有子类可见。可以修饰变量、方法。注意:不能修饰类(外部类)。

访问修饰符和可见性

this 关键字有什么作用?

this 是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。

this 的用法在 Java 中大体可以分为 3 种:

  1. 普通的直接引用,this 相当于是指向当前对象本身
  2. 形参与成员变量名字重名,用 this 来区分:
public Person(String name,int age){
    this.name=name;
    this.age=age;
}
  1. 引用本类的构造函数

抽象类 (abstract class) 和接口 (interface) 有什么区别?

  1. 接⼝的⽅法默认是 public ,所有⽅法在接⼝中不能有实现 (Java 8 开始接⼝⽅法可以有默认实现),⽽抽象类可以有⾮抽象的⽅法。
  2. 接⼝中除了 static 、 final 变量,不能有其他变量,⽽抽象类中则不⼀定。
  3. ⼀个类可以实现多个接⼝,但只能实现⼀个抽象类。接⼝⾃⼰本身可以通过 extends 关键字扩展多个接⼝。
  4. 接⼝⽅法默认修饰符是 public ,抽象⽅法可以有 public 、 protected 和 default 这些修饰符(抽象⽅法就是为了被重写所以不能使⽤ private 关键字修饰!)。
  5. 从设计层⾯来说,抽象是对类的抽象,是⼀种模板设计,⽽接⼝是对⾏为的抽象,是⼀种⾏为的规范。
  1. 在 JDK8 中,接⼝也可以定义静态⽅法,可以直接⽤接⼝名调⽤。实现类和实现是不可以调⽤的。如果同时实现两个接⼝,接⼝中定义了⼀样的默认⽅法,则必须重写,不然会报错。
  2. jdk9 的接⼝被允许定义私有⽅法 。

总结⼀下 jdk7~jdk9 Java 中接⼝的变化:

  1. 在 jdk 7 或更早版本中,接⼝⾥⾯只能有常量变量和抽象⽅法。这些接⼝⽅法必须由选择实现接⼝的类实现。
  2. jdk 8 的时候接⼝可以有默认⽅法和静态⽅法功能。
  3. jdk 9 在接⼝中引⼊了私有⽅法和私有静态⽅法。

成员变量与局部变量的区别有哪些?

  1. 从语法形式上看:成员变量是属于类的,⽽局部变量是在⽅法中定义的变量或是⽅法的参数;成员变量可以被 public , private , static 等修饰符所修饰,⽽局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
  2. 从变量在内存中的存储⽅式来看:如果成员变量是使⽤ static 修饰的,那么这个成员变量是属于类的,如果没有使⽤ static 修饰,这个成员变量是属于实例的。对象存于堆内存,如果局部变量类型为基本数据类型,那么存储在栈内存,如果为引⽤数据类型,那存放的是指向堆内存对象的引⽤或者是指向常量池中的地址。
  3. 从变量在内存中的⽣存时间上看:成员变量是对象的⼀部分,它随着对象的创建⽽存在,⽽局部变量随着⽅法的调⽤⽽⾃动消失。
  4. 成员变量如果没有被赋初值:则会⾃动以类型的默认值⽽赋值(⼀种情况例外: 被 final 修饰的成员变量也必须显式地赋值),⽽局部变量则不会⾃动赋值。

静态变量和实例变量的区别?静态方法、实例方法呢?

静态变量和实例变量的区别?

静态变量: 是被 static 修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个副本。

实例变量: 必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。

静态⽅法和实例⽅法有何不同?

类似地。

静态方法:static 修饰的方法,也被称为类方法。在外部调⽤静态⽅法时,可以使⽤ “ 类名. ⽅法名 “的⽅式,也可以使⽤” 对象名. ⽅法名 “ 的⽅式。静态方法里不能访问类的非静态成员变量和方法。

实例⽅法:依存于类的实例,需要使用 “ 对象名. ⽅法名 “ 的⽅式调用;可以访问类的所有成员变量和方法。

final 关键字有什么作用?

final 表示不可变的意思,可用于修饰类、属性和方法:

  • 被 final 修饰的类不可以被继承

  • 被 final 修饰的方法不可以被重写

  • 被 final 修饰的变量不可变,被 final 修饰的变量必须被显式第指定初始值,还得注意的是,这里的不可变指的是变量的引用不可变,不是引用指向的内容的不可变。

    例如:

    final StringBuilder sb = new StringBuilder("abc");
            sb.append("d");
            System.out.println(sb);  //abcd

    一张图说明:

final、finally、finalize 的区别?

  • final 用于修饰变量、方法和类:final 修饰的类不可被继承;修饰的方法不可被重写;修饰的变量不可变。

  • finally 作为异常处理的一部分,它只能在 try/catch 语句中,并且附带一个语句块表示这段语句最终一定被执行(无论是否抛出异常),经常被用在需要释放资源的情况下,System.exit (0) 可以阻断 finally 执行。

  • finalize 是在 java.lang.Object 里定义的方法,也就是说每一个对象都有这么个方法,这个方法在 gc 启动,该对象被回收的时候被调用。

    一个对象的 finalize 方法只会被调用一次,finalize 被调用不一定会立即回收该对象,所以有可能调用 finalize 后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会再次调用 finalize 了,进而产生问题,因此不推荐使用 finalize 方法。

== 和 equals 的区别?

== : 它的作⽤是判断两个对象的地址是不是相等。即,判断两个对象是不是同⼀个对象 (基本数据类型 **== **比较的是值,引⽤数据类型 == 比较的是内存地址)。

equals() : 它的作⽤也是判断两个对象是否相等。但是这个 “相等” 一般也分两种情况:

  • 默认情况:类没有覆盖 equals() ⽅法。则通过 equals() 比较该类的两个对象时,等价于通过 “**==**” 比较这两个对象,还是相当于比较内存地址。
  • 自定义情况:类覆盖了 equals() ⽅法。我们平时覆盖的 equals() 方法一般是比较两个对象的内容是否相同,自定义了一个相等的标准,也就是两个对象的值是否相等。

举个例⼦,Person,我们认为两个人的编号和姓名相同,就是一个人:

public class Person {
    private String no;
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person person = (Person) o;
        return Objects.equals(no, person.no) &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(no, name);
    }
}

hashCode 与 equals?

这个也是面试常问——“你重写过 hashcode 和 equals 么,为什么重写 equals 时必须重写 hashCode ⽅法?”

什么是 HashCode?

hashCode() 的作⽤是获取哈希码,也称为散列码;它实际上是返回⼀个 int 整数,定义在 Object 类中, 是一个本地⽅法,这个⽅法通常⽤来将对象的内存地址转换为整数之后返回。

public native int hashCode();

哈希码主要在哈希表这类集合映射的时候用到,哈希表存储的是键值对 (key-value),它的特点是:能根据“键” 快速的映射到对应的“值”。这其中就利⽤到了哈希码!

为什么要有 hashCode?

上面已经讲了,主要是在哈希表这种结构中用的到。

例如 HashMap 怎么把 key 映射到对应的 value 上呢?用的就是哈希取余法,也就是拿哈希码和存储元素的数组的长度取余,获取 key 对应的 value 所在的下标位置。详细可见:面渣逆袭:Java 集合连环三十问

为什么重写 equals 时必须重写 hashCode ⽅法?

如果两个对象相等,则 hashcode ⼀定也是相同的。两个对象相等,对两个对象分别调⽤ equals ⽅法都返回 true。反之,两个对象有相同的 hashcode 值,它们也不⼀定是相等的 。因此,equals ⽅法被覆盖过,则 hashCode ⽅法也必须被覆盖。

hashCode() 的默认⾏为是对堆上的对象产⽣独特值。如果没有重写 hashCode() ,则该 class 的两个对象⽆论如何都不会相等(即使这两个对象指向相同的数据)

为什么两个对象有相同的 hashcode 值,它们也不⼀定是相等的?

因为可能会碰撞, hashCode() 所使⽤的散列算法也许刚好会让多个对象传回相同的散列值。越糟糕的散列算法越容易碰撞,但这也与数据值域分布的特性有关(所谓碰撞也就是指的是不同的对象得到相同的 hashCode()。

Java 是值传递,还是引用传递?

Java 语言是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的。

JVM 的内存分为堆和栈,其中栈中存储了基本数据类型和引用数据类型实例的地址,也就是对象地址。

而对象所占的空间是在堆中开辟的,所以传递的时候可以理解为把变量存储的对象地址给传递过去,因此引用类型也是值传递。

Java 引用数据值传递示意图

深拷贝和浅拷贝?

  • 浅拷贝:仅拷贝被拷贝对象的成员变量的值,也就是基本数据类型变量的值,和引用数据类型变量的地址值,而对于引用类型变量指向的堆中的对象不会拷贝。
  • 深拷贝:完全拷贝一个对象,拷贝被拷贝对象的成员变量的值,堆中的对象也会拷贝一份。

例如现在有一个 order 对象,里面有一个 products 列表,它的浅拷贝和深拷贝的示意图:

浅拷贝和深拷贝示意图

因此深拷贝是安全的,浅拷贝的话如果有引用类型,那么拷贝后对象,引用类型变量修改,会影响原对象。

浅拷贝如何实现呢?

Object 类提供的 clone() 方法可以非常简单地实现对象的浅拷贝。

深拷贝如何实现呢?

  • 重写克隆方法:重写克隆方法,引用类型变量单独克隆,这里可能会涉及多层递归。
  • 序列化:可以先讲原对象序列化,再反序列化成拷贝对象。

Java 创建对象有哪几种方式?

Java 中有以下四种创建对象的方式:

  • new 创建新对象
  • 通过反射机制
  • 采用 clone 机制
  • 通过序列化机制

前两者都需要显式地调用构造方法。对于 clone 机制, 需要注意浅拷贝和深拷贝的区别,对于序列化机制需要明确其实现原理,在 Java 中序列化可以通过实现 Externalizable 或者 Serializable 来实现。

文章作者: stormling
文章链接: http://www.stormling.top/posts/56665.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 码农Stormling!
Java基础核心
cover of previous post
上一篇
Java系列(三)| 常用类
StringString 是 Java 基本数据类型吗?可以被继承吗? String 是 Java 基本数据类型吗? 不是。Java 中的基本数据类型只有 8 个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(reference type)。 String 是一个比较特殊的引用数据类型。 String 类可以继承吗? 不行。String 类使用 final 修饰,是所谓的不可变类,无法被继承。 String 和 StringBuilder、StringBuffer 的区别? String:String 的值被创建后不能修改,任何对 String 的修改都会引发新的 String 对象的生成。 StringBuffer:跟 String 类似,但是值可以被修改,使用 synchronized 来保证线程安全。 StringBuilder:StringBuffer 的非线程安全版本,性能上更高一些。 String str1 = new String(“abc”)...
cover of next post
下一篇
Java系列(一)| 基础语法
Java 概述什么是 Java?Java 是一门面向对象的编程语言,不仅吸收了 C++ 语言的各种优点,还摒弃了 C++ 里难以理解的多继承、指针等概念,因此 Java 语言具有功能强大和简单易用两个特征。Java 语言作为静态面向对象编程语言的优秀代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。 Java 语言有哪些特点?Java 语言有很多优秀(可吹)的特点,以下几个是比较突出的: Java 语言特点 面向对象(封装,继承,多态); 平台无关性:Java 是 “【一次编写,到处运行(Write Once,Run any Where)】” 的语言,因此采用 Java 语言编写的程序具有很好的可移植性,而保证这一点的正是 Java 的虚拟机机制。在引入虚拟机之后,Java 语言在不同的平台上运行不需要重新编译。 支持多线程:C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计 编译与解释并存; JVM、JDK 和 JRE 有什么区别?JVM:Java Virtual Machine,Java 虚拟机,Java...
相关推荐
cover
2021-09-19
Java系列(五)| 序列化、泛型、注解、反射
序列化什么是序列化?什么是反序列化?什么是序列化,序列化就是把 Java 对象转为二进制流,方便存储和传输。 所以反序列化就是把二进制流恢复成对象。 序列化和反序列化 类比我们生活中一些大件物品的运输,运输的时候把它拆了打包,用的时候再拆包组装。 Serializable 接口有什么用? 这个接口只是一个标记,没有具体的作用,但是如果不实现这个接口,在有些序列化场景会报错,所以一般建议,创建的 JavaBean 类都实现 Serializable。 serialVersionUID 又有什么用? serialVersionUID 就是起验证作用。 private static final long serialVersionUID = 1L; 我们经常会看到这样的代码,这个 ID 其实就是用来验证序列化的对象和反序列化对应的对象 ID 是否一致。 这个 ID 的数字其实不重要,无论是 1L 还是 IDE 自动生成的,只要序列化时候对象的 serialVersionUID 和反序列化时候对象的 serialVersionUID 一致的话就行。 如果没有显示指定...
cover
2021-09-19
Java系列(四)| 异常处理及IO
Java 中异常处理体系?Java 的异常体系是分为多层的。 Java 异常体系 Throwable是 Java 语言中所有错误或异常的基类。 Throwable Error:系统内部错误比如虚拟机异常,是程序无法处理的。 Exception:程序问题导致的异常 CheckedException 受检异常:编译器会强制检查并要求处理的异常。 RuntimeException 运行时异常:程序运行中出现异常,比如我们熟悉的空指针、数组下标越界等等 异常的处理方式?针对异常的处理主要有两种方式: 遇到异常不进行具体处理,而是继续抛给调用者 (throw,throws) 抛出异常有三种形式,一是 throw, 一个 throws,还有一种系统自动抛异常。 throws 用在方法上,后面跟的是异常类,可以跟多个;而 throw 用在方法内,后面跟的是异常对象。 try catch 捕获异常 在 catch 语句块中补货发生的异常,并进行处理。 try { //包含可能会出现异常的代码以及声明异常的方法 }catch(Exception e)...
cover
2021-09-18
Java系列(三)| 常用类
StringString 是 Java 基本数据类型吗?可以被继承吗? String 是 Java 基本数据类型吗? 不是。Java 中的基本数据类型只有 8 个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(reference type)。 String 是一个比较特殊的引用数据类型。 String 类可以继承吗? 不行。String 类使用 final 修饰,是所谓的不可变类,无法被继承。 String 和 StringBuilder、StringBuffer 的区别? String:String 的值被创建后不能修改,任何对 String 的修改都会引发新的 String 对象的生成。 StringBuffer:跟 String 类似,但是值可以被修改,使用 synchronized 来保证线程安全。 StringBuilder:StringBuffer 的非线程安全版本,性能上更高一些。 String str1 = new String(“abc”)...
cover
2021-09-16
Java系列(一)| 基础语法
Java 概述什么是 Java?Java 是一门面向对象的编程语言,不仅吸收了 C++ 语言的各种优点,还摒弃了 C++ 里难以理解的多继承、指针等概念,因此 Java 语言具有功能强大和简单易用两个特征。Java 语言作为静态面向对象编程语言的优秀代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。 Java 语言有哪些特点?Java 语言有很多优秀(可吹)的特点,以下几个是比较突出的: Java 语言特点 面向对象(封装,继承,多态); 平台无关性:Java 是 “【一次编写,到处运行(Write Once,Run any Where)】” 的语言,因此采用 Java 语言编写的程序具有很好的可移植性,而保证这一点的正是 Java 的虚拟机机制。在引入虚拟机之后,Java 语言在不同的平台上运行不需要重新编译。 支持多线程:C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计 编译与解释并存; JVM、JDK 和 JRE 有什么区别?JVM:Java Virtual Machine,Java 虚拟机,Java...

评论
ValineGitalk
avatar
stormling
文章
42
标签
25
分类
21
Follow Me
公告
欢迎大家来到Stormling博客
目录
  1. 1. 面向对象和面向过程的区别?
  2. 2. 面向对象有哪些特性
  3. 3. 重载(overload)和重写(override)的区别?
  4. 4. 访问修饰符 public、private、protected、以及不写(默认)时的区别?
  5. 5. this 关键字有什么作用?
  6. 6. 抽象类 (abstract class) 和接口 (interface) 有什么区别?
  7. 7. 成员变量与局部变量的区别有哪些?
  8. 8. 静态变量和实例变量的区别?静态方法、实例方法呢?
  9. 9. final 关键字有什么作用?
  10. 10. final、finally、finalize 的区别?
  11. 11. == 和 equals 的区别?
  12. 12. hashCode 与 equals?
  13. 13. Java 是值传递,还是引用传递?
  14. 14. 深拷贝和浅拷贝?
  15. 15. Java 创建对象有哪几种方式?
最新文章
面向八股文面试专场
面向八股文面试专场2025-01-22
【每日早报】-2025-01-21 - 星期二
【每日早报】-2025-01-21 - 星期二2025-01-21
规则引擎 Drools 8+ 快速入门
规则引擎 Drools 8+ 快速入门2024-12-11
数据库系列(二) | Mybatis Plus 3.0+快速入门
数据库系列(二) | Mybatis Plus 3.0+快速入门2024-12-09
分布式系列(二) | Redisson分布式锁
分布式系列(二) | Redisson分布式锁2024-12-05
©2019 - 2025 By stormling
码农Stormling程序员,关注公众号【码农Stormling】回复【面试】获取最全面试pdf
搜索
数据加载中