Java 类与对象的介绍

一、面向对象简述。
面向对象是一种现在最为流行的程序设计方法,谈到面向对象就不得不提及面向过程。
这是两种不同的程序设计方法,常见的c语言用的是面向过程,而java、c++用的是面向对象。
对两种思想抽象地定义,
面向过程是围绕功能进行的,为每一个功能写一个函数,需要考虑其中的每一个细节,以步骤划分;
而面向对象则像是组装,先确定一个系统是由哪些对象组成,再分别去设计这些对象,将它们像零件一样组装起来形成有完整功能的系统。
再具体举一个常用的例子:用这两种方法分别实现“把大象放进冰箱”。
面向过程:肢解大象-打开冰箱-放入大象-关闭冰箱
面向对象:大象(肢解功能、移动功能)、冰箱(打开功能、装载功能、关闭功能)。

面向对象的三大特性。
(1)封装:保护内部的操作不被破坏; 
(2)继承:在原本的基础之上继续进行扩充; 
(3)多态:在一个指定的范围之内进行概念的转换。

二、类与对象的基本概念

类与对象时整个面向对象中最基础的组成单元。

类:是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法); 
对象:对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
比如说:人类是一个类,每一个人是类中的一个对象,每个人都有身高,体重,性别,外貌等等的属性。
在编程设计中,我们需要定义一个类,再给对应的类定义具体对象。

三、类与对象的定义和使用

类定义范式:

class 类名称{
      属性;
      行为;
}

定义Person类:

class Person{
      String name;//名字
      int height;//身高
      int age;//年龄
      public void walk(){
             System.out.print(name+"会走路");
      }  //走路
      public void tell(){
             System.out.print("名字:"+name+";"年龄:"+age);
      }
}

类定义完成之后,无法直接使用。如果要使用,必须依靠对象,对象的产生格式(两种格式)如下:

(1)格式一:声明并实例化对象

类名称 对象名称 = new 类名(); //格式
Person person = new Person();//Person实例

(2)格式二:先声明对象,再实例化对象

类名称 对象名称 = null;
对象名称 = new 类名(); //格式

Person person = null;
person = new Person(); //Person实例

 不同于int、String、char等基本数据类型,类属于引用数据类型,而引用数据类型在使用时需要用内存空间的分配和使用,关键字new就是用来分配内存的。

实例化一个对象后,可以用关键字"."对对象进行类的操作,比如定义属性具体值,使用方法。

对象名.属性名 = 具体值;
对象名.方法名();

person.age = 18;
person.walk();

接下来用在eclipse实践一下这两种实例化对象的方法。

格式一:

package com.alex.classtest;

class Person { 
    String name ;
    int age ;
    public void get() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Person per = new Person() ;// 声明并实例化对象
            per.name = "张三" ;//操作属性内容
            per.age = 30 ;//操作属性内容
            per.get() ;//调用类中的get()方法
        }
}

运行结果:

姓名:张三,年龄:30

格式二:

package com.alex.classtest;

class Person { 
    String name ;
    int age ;
    public void get() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Person per = null;//声明对象
            per = new Person() ;//实例化对象
            per.name = "张三" ;//操作属性内容
            per.age = 30 ;//操作属性内容
            per.get() ;//调用类中的get()方法
        }
}

运行结果:

姓名:张三,年龄:30

我们可以发现,得到的结果是一样的。那么这两种方式的区别在哪呢?

说到这里就必须从内存的角度来分析。

首先,给出两种内存空间的概念: 
(1)堆内存:保存对象的属性内容。堆内存需要用new关键字来分配空间; 
(2)栈内存:保存的是堆内存的地址(在这里为了分析方便,可以简单理解为栈内存保存的是对象的名字)。

任何情况下,只要看见关键字new,都表示要分配新的堆内存空间,一旦堆内存空间分配了,里面就会有类中定义的属性,并且属性内容都是其对应数据类型的默认值。

上面两种对象实例化对象方式内存表示如下:

两种方式的区别在于①②,第一种声明并实例化的方式实际就是①②组合在一起,而第二种先声明然后实例化是把①和②分步骤来。

如果使用了没有实例化的对象,则会程序运行结果会报错。

package com.alex.classtest;

class Person { 
    String name ;
    int age ;
    public void get() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Person per = null;//声明对象
            //per = new Person() ;//实例化对象
            per.name = "张三" ;//操作属性内容
            per.age = 30 ;//操作属性内容
            per.get() ;//调用类中的get()方法
        }
}

运行结果:

Exception in thread "main" java.lang.NullPointerException
    at com.wz.classandobj.TestDemo.main(TestDemo.java:15)

错误信息表示的是“NullPointerException(空指向异常)”。是因为程序只声明了Person对象,但并没有实例化Person对象(只有了栈内存,并没有对应的堆内存空间),程序在编译的时候不会出现任何的错误,但是在执行的时候出现了上面的错误信息。

 

四、对象引用传递初步分析

引用传递定义上指的是同一块堆内存空间,可以同时被多个栈内存所指向,不同的栈可以修改同一块堆内存的内容。

也就是说同一个对象的属性内存被两个不同命名的对象共同使用。

看下面实例

class Person {
         String name ;
         int age ;
         public void tell() {
                   System.out.println("姓名:" + name + ",年龄:" + age) ;
         }
}
public class TestDemo {
         public static void main(String args[]) {
                   Person per1 = new Person() ;         // 声明并实例化对象
                   Person per2 = new Person() ;
                   per1.name = "张三" ;
                   per1.age = 20 ;
                   per2.name = "李四" ;
                   per2.age = 30 ;
                   per2 = per1 ;// 引用传递
                   per2.name = "王五" ;
                   per1.tell() ;
         }
}
 

输出的结果是:

姓名:王五,年龄:20

在这个过程中,内存空间是这样变化的:

垃圾:指的是在程序开发之中没有任何对象所指向的一块堆内存空间,这块空间就成为垃圾,所有的垃圾将等待GC(垃圾收集器)不定期的进行回收与空间的释放。

五、面向对象的封装性

在定义类时,在class或者属性变量之前加上修饰词public、private、default、protected表示它的被访问权限。

先看属性变量没有修饰词也就是默认(default)的时候,

class Book{

    String title;
    double price;

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book = new Book();
            book.title = "Quanta";
            book.price = 99;
            book.getInfo();
        }
}

输出的结果是:

图书的名称:Quanta 图书的价格:99

当属性变量修饰词为private时:

class Book{

    private String title;
    private double price;

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book = new Book();
            book.title = "Quanta";
            book.price = 99;
            book.getInfo();
        }
}

运行结果:

Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
    The field Book.title is not visible
    The field Book.price is not visible

    at com.wz.classandobj.TestDemo.main(TestDemo.java:16)

也就是在加入private修饰词后无法再Book类的外部直接调用它的属性了。

那么如何在类外部访问Book类内的private(私有)变量呢?这时候可以用到setter、getter方法。

为Book类定义属性相应的setter和getter方法,以Book类为例:

class Book{

    private String title;
    private double price;

    public void setTitle(String title){
        this.title = title;
}
    public String getTitle(){
        return title;
}

    public void setPrice(double price){
        this.price = price;
}
    public double getPrice(){
        return price;
}
    public void getInfo(){
        System.out.println("图书的名称:"+getTitle()+" 图书的价格:"+getPrice());
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book = new Book();
            book.setTitle("Quanta");
            book.setPrice(99);
            book.getInfo();
        }
}

五、类中的构造方法

通常我们实例化对象的时候用的是这样的格式

   ①类名称 ②对象名称 = ③new ④类名称();

①类名称:规定了对象的类型。即:对象可以使用哪些属性和方法都是由类定义的; 
②对象名称:如果需要使用对象,需要有一个名称,这是一个唯一的标记; 
③new:分配新的堆内存空间; 
④类名称():调用了名称和类名称相同的方法,这个地方就是我们所讲的构造方法。

实际上,构造方法一直在被我们调用,但我们并没有去定义它,为什么能够使用呢?这是因为在整个Java开发中,为了保证程序可以正常执行,即便用户没有定义任何构造方法,也会在程序编译后自动为类增加一个没有参数,方法名称与类名称相同,没有返回值的构造方法。

当我们创建一个类时,类中会默认生成一个无参构造方法(只是并没有显示,当我们用默认格式生成对象实例的时候便是调用了该构造方法)。

//无参,无返回值的构造方法
    public Book() {

    }

当我们给构造方法中加入一条打印语句后

class Book{

    private String title;
    private int price;

    //无参,无返回值的构造方法
    public Book() {
        System.out.println("无参构造方法");
    }

}

public class TestDemo {
        public static void main(String args[]) {
            Book book = new Book();//实例化对象,等于调用Book构造方法
        }
}

输出结果:

无参构造方法

自定义带参数的构造方法:

class Book{

    private String title;
    private int price;


    public Book() {
        System.out.println("无参的构造方法");
    }


    public Book(String title) {
        this.title = title;
        System.out.println("有一个参数的构造方法");
    }


    public Book(String title, double price) {
        this.title = title;
        this.price = price;
        System.out.println("有俩个参数的构造方法");
    }

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book1 = new Book();
            book1.getInfo();

            Book book2 = new Book("Quanta");
            book2.getInfo();

            Book book3 = new Book("Quanta",99);
            book3.getInfo();

        }

运行结果:

无参的构造方法
图书的名称:null 图书的价格:0
有一个参数的构造方法
图书的名称:Quanta 图书的价格:0
有俩个参数的构造方法
图书的名称:Quanta 图书的价格:99

可以看到通过默认构造方法创建的book1属性是null和0,而book2有title属性,book3有title和price;

注意:如果定义了带有参数的构造函数,则默认构造函数失效,原来的默认函数(没有参数的默认函数)需手动定义!

六、类中的匿名对象

没名字的对象称为匿名对象,对象的名字按照之前的内存关系来讲,在栈内存之中,而对象的具体内容在堆内存之中保存,这样,没有栈内存指向堆内存空间,就是一个匿名对象。

class Book{

    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
        System.out.println("有俩个参数的构造方法");
    }

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            //匿名对象
            new Book("Quanta",99).getInfo();

        }
}

结果:

有俩个参数的构造方法
图书的名称:Quanta 图书的价格:99

可以看到不用命名对象而直接生成Book类的匿名对象并调用它的方法。

课后实践:编写一个Person类,

(1)Person类有私有属性姓名,性别,年龄,身高;

(2)有方法speak():输出语句“哈哈哈”;

(3)方法tell():输出姓名、性别、年龄、身高;

(4)对应的私有属性要有相应的setter、getter方法;

(5)自定义一个带有全部参数的构造方法;

main函数中要求用默认方式实例化一个对象,再用对应的set方法定义他的属性,另外用自定义的构造方法实例化一个带参数的对象,最后两个对象分别使用tell方法。

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值