Java 面向对象思想

Java 面向对象思想

什么是面向对象

面向对象和面向过程区别

面向过程:面向过程是将解决问题的思路转为一个个方法。 面向对象:面向对象则是编写一个对象,将这些思路封装成一个个对象方法,后续调用这个对象解决问题,相对面向过程而言,这种思路更符合人的思维并且更易扩展、复用、维护。

面向对象和面向过程性能差距:人们常常认为面向过程性能高于面向对象,因为创建的对象开销远远大于面向过程,实际上Java面向对象性能差的原因并不是这个,真正的原因是Java为半编译语言,运行并不是直接拿着二进制机械码执行,而是需要结果字节码转换这一步。 而且面向过程的性能并不一定比面向过程快,面向过程也需要计算偏移量以及某些脚本语言的性能也一定比Java好。

创建一个对象用什么运算符?

用new运算符,创建的对象的实例会在堆内存中开辟一个空间。而引用则在栈内存中,指向对象实例。

面向对象实现伪代码

以人开门为例,人需要开门,所以我们需要创建一个门对象,描述门的特征,这个门可以开或者关。所以门的伪代码如下:

门{
    开()
    {
    操作门轴
    }
}

上文说到了,面向对象的特点就是符合人的思维,而人开门这个功能,我们就可以创建一个人的对象,编写一个开门的动作,把门打开。通过这种对象调用对象的方式完成了功能。后续我们需要狗开门,猫开门也只是编写一个方法调用门对象的开的动作。

人 {
    开门(门对象){
    门.打()
    }
 }

面向对象三大特征

  1. 封装
  2. 继承
  3. 多态

类和对象的关系。

以生活事务为例,现实生活中的对象:张三 李四。他们都有姓名、性别、学习Java的能力。

所以我们要想通过面向对象思想实现抽象出对象,就得提取共性,编写一个类有姓名、性别、学习Java的能力。

public class Student {

    private String name;
    private int sex;

    public void studyJava(){
        System.out.println(this.name+"学习java");
    }
}

描述时,这些对象的共性有:姓名,年龄,性别,学习java功能。再将这些分析映射到java中,就是以class定义的类进行展开。

public static void main(String[] args) {
        Student zhangsan=new Student();
        zhangsan.setName("张三");
        zhangsan.studyJava();

        Student lisi=new Student();
        lisi.setName("李四");
        lisi.studyJava();

//        输出结果
//        张三学习java
//                李四学习java
    }

而具体对象就是对应java在堆内存中用new建立实体。

基础案例

需求:描述汽车(颜色,轮胎数)。描述事物其实就是在描述事物的属性和行为。

属性对应在类中即变量行为对应的类中的函数(方法)

代码实现

public class Car {
    //描述颜色
    String color = "红色";
    //描述轮胎数
    int num = 4;

    //运行行为。
    public void run() {

        System.out.println("颜色:"+color + " 轮胎数:" + num);
    }
}

实例化

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.run();
    }
}

创建car对象时car引用的内存图

img

对象调用方法过程

首先我们看一段代码,这是一个人类的class类代码

public class Person {
    private String name;
    private int age;
    private static String country = "cn";

    public Person(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 static void showCountry() {
        System.out.println("showCountry " + country);
    }


    public void speak() {
        System.out.println(this.getName() + " speak");
    }
}

假如我们在main中编写这样一段代码,请问在内存中他是如何工作的呢?

 public static void main(String[] args) {
        Person p = new Person("张三", 18);
        p.setName("李四");
    }

我们先从类类加载时开始分析,由于static关键字修改的变量或者方法会随着jvm加载类时一起创建,所以country和showCountry()在方法区是这样的。

img

然后main方法开始执行对应代码,首先main方法入栈,初始化一个p引用

img

调用setName,setName入栈,完成name值修改之后销毁

img

成员变量和局部变量

作用范围

成员变量作用于整个类中。 局部变量变量作用于函数中,或者语句中。

在内存中的位置

成员变量:在堆内存中,因为对象的存在,才在内存中存在。 局部变量:存在栈内存中。

关于对象的引用关系

简介

对象引用用于指向0个或者多个对象实例,对象实例可以被多个对象引用指向。

相关代码

假如我们使用上文car类执行以下代码,那么在内存中会如何执行呢?

car c=new car();
c.num=5;
car c1=c;
c.run();

内存图解

  1. 首先堆区开辟一个空间创建car对象,初始化值
  2. 修改num为5
  3. c1引用指向c,如下图所示

img

对象相等和引用相等的区别

  1. 对象相等:两个对象内存中的存放的内容都相等
  2. 引用相等:两个引用指向的内存地址相等。

类的构造方法的作用是什么

完成对象初始化,首先在堆区创建对象实例。

构造方法的特点

  1. 与类名相同
  2. 无返回值
  3. 生成对象时自动执行
  4. 不可重写可以重载

深拷贝和浅拷贝区别

浅拷贝

对象进行拷贝时,如果内部有引用类型,克隆对象仅仅是复制被克隆内部对象的引用地址

为了介绍浅拷贝我们贴出这样一段代码,可以看到一个学生类有id和name,以及一个Vector的引用对象

public class Student implements Cloneable {
    private String id;
    private String name;
    private Vector<String> vector;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Vector<String> getVector() {
        return vector;
    }

    public void setVector(Vector<String> vector) {
        this.vector = vector;
    }


    public Student() {
        try {
            System.out.println("创建对象需要三秒......");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public Student newInstance() {
        try {
            return (Student) this.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return null;
    }


}

然后我们使用下面这段代码进行测试,可以看到输出结果为true,说明student2的vector是student1的。如下图所示,克隆对象的内部引用对象和student1是通用的

@Test
    public void cloneTest() throws CloneNotSupportedException {

        long start,end;
        start=System.currentTimeMillis();
        Student student=new Student();
        end=System.currentTimeMillis();
        System.out.println("学生1创建时间长 "+(end-start));


        student.setId("1");
        student.setName("小明");
        Vector<String> v = new Vector<>();
        v.add("000000");
        v.add("000001");
        student.setVector(v);

        start=System.currentTimeMillis();
        Student student2= student.newInstance();
        end=System.currentTimeMillis();
        System.out.println("学生2创建时间长 "+(end-start));


        for (String s : student2.getVector()) {
            System.out.println(s);
        }
//        false则说明深拷贝成功
        System.out.println(student.getVector()==student2.getVector());
    }

img

深拷贝

了解了浅拷贝之后,我们就可以解释深拷贝了,克隆对象的内部引用对象都是全新复制出来的一份

基于上文student代码我们对此进行改造,重写以下clone方法

@Override
    protected Object clone() throws CloneNotSupportedException {
        Student clone = new Student();
        clone.setId(this.getId());
        clone.setName(this.getName());

        //避免clone导致浅拷贝问题
        Vector<String> srcVector = this.getVector();

        Vector<String> dstVector = new Vector<>();
        for (String v : srcVector) {
            dstVector.add(v);
        }

        clone.setVector(dstVector);

        return clone;

    }

img

匿名对象

实例代码

如下所示,在堆区创建一个对象实例,用后即被销毁。为了介绍匿名对象,我们首先需要编写一个汽车类

public class Car {
    //描述颜色
    private String color = "红色";
    //描述轮胎数
    private int num = 4;

    public String getColor() {
        return color;
    }

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

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    //运行行为。
    public void run() {
        this.setNum(++num);
        System.out.println("颜色:"
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值