Java面向对象【Java面试题】

x33g5p2x  于2021-11-09 转载在 Java  
字(8.2k)|赞(0)|评价(0)|浏览(406)

1、面向对象包括哪些特性,怎么理解的?

(1)封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。
面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。
我们在类中编写的方法就是对实现细节的一种封装;
我们编写一个类就是对数据和数据操作的封装。
可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。

package cn.itbluebox.springbootactuator;
class A{
    private String name;
    private int age;
    public A() {
    }
    public A(String name, int age) {
        this.name = name;
        this.age = 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 class Test {
    public static void main(String[] args) {
        A a = new A();
        a.setAge(12);
        a.setName("张三");
        int age = a.getAge();
        String name = a.getName();
        System.out.println("age"+age);
        System.out.println("name"+name);
    }
}

运行测试

(2)继承:继承是从已有类得到继承信息创建新类的过程。
提供继承信息的类被称为父类(超类、基类);
得到继承信息的类被称为子类(派生类)。
继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。

package cn.itbluebox.springbootactuator;

class A{
    public void a(){
        System.out.println("aaaaaaaa");
    }
}
class B extends A{
}
public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.a();
    }
}

(3)多态:多态性是指允许不同子类型的对象对同一消息作出不同的响应。
简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。
多态性分为编译时的多态性和运行时的多态性。
如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:
当 A系统访问B系统提供的服务时,B 系统有多种提供服务的方式,但一切对 A 系统来说都是透明的。
方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。
运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:

第一:方法重写(子类继承父类并重写父类中已有的或抽象的方法);

第二:对象造型(用父类型引用指向子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

package cn.itbluebox.springbootactuator;
class A{
    public void a(){
        System.out.println("aaaaaaaa");
    }
    public void o(){
        System.out.println("bobobobobobo");
    }
}
class B extends A{
    public void o(){
        System.out.println("bobobobobobo");
    }
}
class C extends A{
    public void o(){
        System.out.println("cocococococo");
    }
}
public class Test {
    public static void main(String[] args) {
        A a = new B();
        a.o();
        a = new C();
        a.o();
    }
}

(4)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

package cn.itbluebox.springbootactuator;
abstract class A{
    public abstract void o();
}
class B extends A{
    @Override
    public void o() {
        System.out.println("bobobo");
    }
}
class C extends A{
    @Override
    public void o() {
        System.out.println("cococo");
    }
}
public class Test {
    public static void main(String[] args) {
        A a = new B();
        a.o();
        a = new C();
        a.o();
    }
}

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

3、Java中为什么要用 clone?

在实际编程过程中,我们常常要遇到这种情况:
有一个对象 A,在某一时刻 A 中已经包含了一些有效值,此时可能会需要一个和 A 完全相同新对象 B,并且此后对 B 任何改动都不会影响到 A 中的值,也就是说,A 与 B 是两个独立的对象,但 B 的初始值是由 A 对象确定的。
在 Java 语言中,用简单的赋值语句是不能满足这种需求的。
要满足这种需求虽然有很多途径,但clone()方法是其中最简单,也是最高效的手段。

● 说到对象的克隆,涉及到深克隆和浅克隆?

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

new一个对象的过程和clone一个对象的区别?
new 操作符的本意是分配内存。程序执行到 new 操作符时,首先去看 new 操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。

分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。

clone 在第一步是和 new 相似的,都是分配内存,调用 clone 方法时,分配的内存和原对象(即调用 clone 方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域,填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

(1)实际案例

1)单纯的复制对象
package cn.itbluebox.springbootactuator;

class Student{
    private int age;
    private String name;
    public Student() {
    }
    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student();
        student1.setAge(12);
        Student student2 = student1;
        System.out.println("学生1:" + student1.getAge());
        System.out.println("学生2:" + student2.getAge());
    }
}

运行

当我们更改student1的值的时候student2也会被修改

package cn.itbluebox.springbootactuator;

class Student{
    private int age;
    private String name;
    public Student() {
    }
    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student();
        student1.setAge(12);
        Student student2 = student1;
        student1.setAge(30);
        System.out.println("学生1:" + student1.getAge());
        System.out.println("学生2:" + student2.getAge());
    }
}

原因出在(student2= student1) 这一句。该语句的作用是将student1的引用赋值给student2,

这样,student1和student2指向内存堆中同一个对象。

修改其中一个则另外一个也会改变

2)如何实现克隆
01)浅克隆
  1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常), 该接口为标记接口(不含任何方法)
  2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。(native为本地方法)

在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

package cn.itbluebox.springbootactuator;

class Student implements Cloneable{
    private int age;
    private String name;
    public Student() {
    }
    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Object clone() {
        Student stu = null;
        try{
            stu = (Student)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student();
        student1.setAge(12);
        Student student2 = (Student)student1.clone();
        student1.setAge(30);
        System.out.println("学生1:" + student1.getAge());
        System.out.println("学生2:" + student2.getAge());
    }
}

student1在赋值年龄12之后clone创建student2 ,然后更改student1的值是不会影响student2 的值的

02)深度克隆:

在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。
错误案例

package cn.itbluebox.springbootactuator;

class Address{
    private String add;
    public Address() {
    }
    public Address(String add) {
        this.add = add;
    }
    public String getAdd() {
        return add;
    }
    public void setAdd(String add) {
        this.add = add;
    }
}
class Student implements Cloneable{
    private int age;
    private Address address;
    public Student() {
    }
    public Student(int age, Address address) {
        this.age = age;
        this.address = address;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    @Override
    public Object clone() {
        Student stu = null;
        try{
            stu = (Student)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}
public class Test {
    public static void main(String[] args) {
        Address addr = new Address();
        addr.setAdd("杭州市");
        Student student1 = new Student();
        student1.setAge(12);
        student1.setAddress(addr);
        Student student2 = (Student)student1.clone();
        student1.setAge(30);
        Address addr2 = new Address();
        addr.setAdd("北京");
        student1.setAddress(addr2);
        System.out.println("学生1:" + student1.getAge()+"地址:"+student1.getAddress().getAdd());
        System.out.println("学生2:" + student2.getAge()+"地址:"+student2.getAddress().getAdd());
    }
}

student1在赋值年龄12和地址为杭州之后clone创建student2 ,然后更改student1的值是不会影响student2 的值的,但是student2 当中address的add更改了,并且student1的地址没有了

因为上述Address没有实现Cloneable接口没有重写clone()方法

更改Address类

package cn.itbluebox.springbootactuator;

class Address implements Cloneable {
    private String add;

    public Address() {
    }

    public Address(String add) {
        this.add = add;
    }

    public String getAdd() {
        return add;
    }

    public void setAdd(String add) {
        this.add = add;
    }

    @Override
    public Object clone() {
        Address addr = null;
        try {
            addr = (Address) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return addr;
    }
}

class Student implements Cloneable {
    private int age;
    private Address address;

    public Student() {
    }

    public Student(int age, Address address) {
        this.age = age;
        this.address = address;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public Object clone() {
        Student stu = null;
        try {
            stu = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        stu.address = (Address)address.clone();   //深度复制
        return stu;
    }
}

public class Test {
    public static void main(String[] args) {
        Address addr = new Address();
        addr.setAdd("杭州市");
        Student stu1 = new Student();
        stu1.setAge(123);
        stu1.setAddress(addr);

        Student stu2 = (Student)stu1.clone();
        System.out.println("学生1:" + stu1.getAge() + ",地址:" + stu1.getAddress().getAdd());
        System.out.println("学生2:" + stu2.getAge() + ",地址:" + stu2.getAddress().getAdd());

        addr.setAdd("西湖区");
        System.out.println("学生1:" + stu1.getAge() + ",地址:" + stu1.getAddress().getAdd());
        System.out.println("学生2:" + stu2.getAge() + ",地址:" + stu2.getAddress().getAdd());
    }
}

相关文章