Java 学习笔记:第四章 Java面向对象基础

Java编程:面向对象基础解析
本文介绍了Java面向对象的基础知识,包括面向过程与面向对象的区别、面向对象的思考方式,以及对象的进化史。重点讲解了类和对象的概念,属性、方法、构造器的定义,以及内存分析中的栈、堆和方法区特点。此外,还探讨了构造方法的重载、垃圾回收机制和this关键字的使用。最后提到了静态成员变量、静态初始化块以及参数传递机制。

4.1 面向过程和面向对象

面向过程(Procedure Oriented)和面向对象 (Object Oriented ,OO)都是对软件分析、设计和开发的一种思想,它指导人们以不同的方式去分析、设计和开发软件。早期先有面向过程思想,随着软件规模的扩大,问题复杂性的提高,面向过程的弊端越来越明显的显示出来,出现了面向对象思想并成为目前主流的方式。两者都贯穿于软件分析、设计和开发各个阶段,对应面向对象就分别称为面向对象分析(OOA)、面向对象设计(OOD)和面向对象编程(OOP)。C语言是一种典型的面向的过程语言,Java 是一种典型的面向对象语言。

面向过程思想思考问题时,我们首先思考 “怎么按步骤实现?”并将步骤对应成方法,一步一步最终完成。这个适合简单任务,不需要过多协作的情况下。比如,如何开车?我们很容易就列出实现步骤:

1 发动车 2 挂挡 3 踩油门 4 走你

面向过程适合简单、不需要协作的事务。但是当我们思考比较复杂的问题,比如 “如何造车”,就会发现列出 1234 这样的步骤,是不可能的。那是因为,造车太复杂,需要很多协作才能额按成。此时面向对象思想就应运而生了。

面向对象(Object)思想更契合人的思想模式。我们首先思考的是 “怎么设计这个事物” 比如 思考造车 ,我们就会先思考 “车是怎么设计”,而不是“怎么按步骤造车的问题”。这就是思维方式的转变。

一、 面向对象思想思考造车,发现车由如下对象组成:

  1. 轮胎
  2. 发动机
  3. 车壳
  4. 座椅
  5. 挡风玻璃

为了便于协作,我们找轮胎厂完成制造轮胎的步骤,发动机厂完成制造发动机的步骤;这样,发现大家可以同时进行车的制造,最终进行组装,大大提高了效率 。但是,具体到轮胎厂的一个流水线操作,仍然是有步骤的,还是刘不开面向过程思想!

因此,面向对象可以帮助我们从宏观上把握从整体上分析整个系统。但是,具体到实现部分的微观操作,仍然需要面向过程的思路去解决。

我们千万不要 把面向过程和面向对象对立起来。它们是相辅相成的。面向对象离不开面向过程!

面向对象和面向过程的总结

  1. 都是解决问题的思维方式,都是代码组织的方式。
  2. 解决简单问题可以使用面向过程
  3. 解决复杂问题:宏观上使用面向对象把握,围观处理上仍然是面向过程。

面向对象思考方式

遇到复杂问题,先从问题中找名词。然后确立这些名词哪些可以作为类,在根据问题需求确定的类的属性和方法,确定类之间的关系。

建议

  1. 面向对象具有三大特征:封装性、继承性和多态性,而面向过程没有继承性和多态性,并且面向过程的封装只是封装功能,而面向对象可以封装数据和功能。所以面向对象优势更明显。
  2. 一个经典的比喻:面向对象是盖浇饭、面向过程是蛋烧饭。盖浇饭的好处就是 菜 饭分离,从而提高了制作盖浇饭的灵活性。饭不满意就换饭,菜不满意换菜。用软件工程的专业术语就是 可维护性 比较好。

4.2 对象的进化史

事物的发展总是遵循 “量变引起质变”的哲学原则。

  • 数据无管理时代

最初的计算机语言只有基本变量(类似我们学习的基本数据类型),用来保存数据。那时候面对的数据非常简单,只需要几个变量即可搞定;这个时候不涉及“数据管理”的问题。同理,就像在企业最初发展阶段只有几个人 ,不涉及管理问题,大家闷头做事就ok 了。

  • 数组管理和企业部门化

企业发展中,员工多了怎么办?我们很自然的想法就是归类,将类型一致的人放到一起企业中,会将都做销售工作的放到销售部管理;会将研发软件的放到开发部管理。同理在编程中,变量多了,我们很容易的想法就是“将同类型数据放到一起”,于是就形成了“数组”的概念,单词对应“array”。这种“归类”的思想,便于管理数据和人。

  • 对象和企业项目制

企业继续发展,面对的场景更加复杂。一个项目可能需要经常协同多个部门才能完成工作;一个项目从谈判接触可能需要销售部介入;谈判完成后,需求调研开始,研发部和销售部一起介入;开发阶段需要开发部和测试部互相配合敏捷开发,同时整个过程财务部也需要跟进。在企业中,为了便于协作和管理,很自然就兴起了 “项目制” ,以项目组的形式组织,一个项目组可能包含各种类型的人员。一个完整的项目组,麻雀虽小五脏俱全,就是个创公司甚至小型公司的编制,包含行政后勤人员、财务核算人员、开发人员、售前人员、售后人员、测试人员、设计人员等等。事实上,华为、腾讯、阿里巴巴等大型公司内部都是采用这种“项目制”的方式进行管理。

同理,计算机编程继续发展,各种类型的变量更加多了,而且对数据的操作也复杂了怎么办?

为了便于协作和管理,我们“将相关数据和相关方法封装在一个独立的实体”,于是,“对象”产生了。比如,我们的一个学生对象:

有属性(静态特征):年龄:18,姓名:高淇,学号:1234

也可以有方法(动态行为):学习,吃饭,考试

请大家举一反三,根据上表理解一下企业的进化史,会发现大道至简。原来,数据管理、企业管理、社会发展也是有很多共通的地方。“量变引起质变,不同的数量级必然采用不同的管理模式”。

4-1 对象进化史和企业进化史

对象进化史

企业进化史

抽象类比

数据少时

基本类型数据阶段

人少时

作坊时代

无管理时代

(对数据或人没有任何管理)

数据多了

数组

同类型数据存到数组中

人多了

部门

工作行为一样的在一个部门

弱管理时代

(将同类型数据集中进行管理)

数据多了

数据关系/操作复杂了

类和对象

将数据和相关的操作行为放到一起

人多了,

业务更复杂,

人的工作行为也复杂

项目组

将不同类型的人放到一起实现统一管理

强管理时代

(将数据和数据操作/人和人的行为 放到一起管理)

总结

  1. 对象说白了也是一种数据结构(对数据的管理模式),将数据和数据的行为放到了一起。
  2. 在内存上,对象是一个内存块,存放了相关的数据集合!
  3. 对象的本质就是一种数据的组织方式!

4.3 对象和类

我们人认识世界,其实就是面向对象的。比如现在让大家认识一下天使 这个新事物,天使大家没见过吧,怎么样认识呢?最好的办法就是,给你们面前摆4个天使,带翅膀的美女,让大家看,看完以后,即使我不说,大家下一次是不是就都认识天使了。

在这里插入图片描述

但是,看完10个天使后,我们总要总结一下,什么样的东东才算天使?天使是无数的,总有没见过的!所以必须总结抽象,便于总结位置事物!总结的过程就是抽象的过程。小时候,我们学自然数时怎么定义的?像1,2,3。。。这样的数叫做自然数。通过抽象,我们发现天使有这样一下特征:

  1. 带翅膀(带翅膀不一定是天使,还可能是鸟人)
  2. 女孩(天使掉下来脸着地,也是天使!)
  3. 善良
  4. 头上有光环

那么通过这4个具体的天使,我们进行抽象,抽象出了天使的特征,我们也可以归纳一个天使类。通过这个过程,类就是对象的抽象。

类可以看做是一个模板,或者图纸,系统根据类的定义来造出对象。我们要在一个汽车,怎么样造?类就是这个图纸,规定汽车的详细信息,然后根据图纸将汽车造出来。

类:我们叫做class 。 对象:我们叫做 Object ,instance 。以后我们说某个类的对象,某个类的实例。是一样的意思。

总结

  1. 对象是具体的事物;类是对对象的抽象;
  2. 类可以看成一类对象的模板,对象可以看成该类的一个具体实例。
  3. 类是用于描述同一类型的对象的一个抽象概念,类中定义了这一类对象所应具有的共同的属性、方法。

4.3.1 第一个类定义

【示例4-1】类的定义方式

// 每一个源文件必须有且只有一个public class,并且类名和文件名保持一致!
public class Car { 
}
class Tyre { // 一个Java文件可以同时定义多个class
}
class Engine {
}
class Seat {
}

上面的类定义好后,没有任何的其他信息,就跟我们拿到一张图纸,但是值得航没有任何信息,这是一个空类,没有任何意义。所以我们需要定义类的具体信息。对于一个类来说,一般有三种常见的成员:属性 field 、方法 method 、 构造器 constructor。这三种成员都可以定义零个或多个。

【示例4-2】简单的学生类编写

public class SxtStu {
    //属性(成员变量)
    int id;
    String sname;
    int age;  
    //方法
    void study(){
        System.out.println("我正在学习!");
    }  
    //构造方法
   SxtStu(){
   }
}

4.3.2 属性(field,或者叫做成员变量)

属性用于定义该类对象包含的数据或者说静态特征。属性作用范围是整个类体。

在定义成员变量时 可以对其初始化,如果不对其初始化,Java 使用默认的值对其初始化。

4-2 成员变量的默认值

数据类型

默认值

整型

0

浮点型

0.0

字符型

'\u0000'

布尔型

false

所有引用类型

null

属性定义格式:

[修饰符]  属性类型  属性名 = [默认值] ;

4.3.3 方法

方法用于定义该类或该类实例的行为特性和功能实现。方法是类和对象行为特性的抽象。方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。

方法定义格式:

[修饰符]  方法返回值类型  方法名(形参列表) {
    // n条语句
}

4.3.4 一个典型类定义和UML图

【示例4-3】模拟学生使用电脑学习

class Computer {
    String brand;  //品牌
}
public class SxtStu {
    // field
    int id;
    String sname;
    int age;
    Computer comp;
    void study() {
        System.out.println("我正在学习!使用我们的电脑,"+comp.brand);
    }
    SxtStu() {
    }
    public static void main(String[] args) {
        SxtStu stu1 = new SxtStu();
        stu1.sname = "张三";
        Computer comp1 = new Computer();
         comp1.brand = "联想";
        stu1.comp = comp1;
        stu1.study();
    }
}

在这里插入图片描述
对应的UML图如下:

在这里插入图片描述

4.4 面向对象内存分析

为了让大家对于面向对象编程有更深入的了解,我们要对程序的执行过程中,内存到底发生什么变化进行剖析,让大家做到“心中有数”,通过更加形象方式理解程序的执行方式。

建议:

  1. 本节课为了让初学者更深入了解程序底层执行情况,为了完整的体现内存分析流程,会有些新的名词,比如:线程、Class 对象。大家暂时可以不求甚解的了解,后期学习了这两个概念在回头来看我们这篇内存分析,肯定收货会更大。

Java 虚拟机的内存可以分为 单个区域:栈 stack 、堆 heap 、方法区 method area。

栈的特点

  1. 栈描述的是方法执行的内存模型。每个方法会被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
  2. JVM 为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
  3. 栈属于线程私有,不能实现线程间的共享!
  4. 栈的存储特性是“先进后出,后进先出”
  5. 栈是由系统自动分配,速度快!栈是一个连续的内存空间!

堆的特点

  1. 堆用于存储创建好的对象和数组(数组也是对象)
  2. JVM 只有一个堆,被所有线程共享
  3. 堆是一个不连续的内存空间,分配灵活,速度慢!

方法区特点

  1. JVM 只有一个方法区,被所有线程共享!
  2. 方法区实际也是堆,只是用于存储类、常量相关的信息!
  3. 同来存放程序中永远是不变或唯一的内容。(类信息【Class 对象】、静态变量、字符串常量等)

在这里插入图片描述

在这里插入图片描述

4.5 构造方法

构造器也叫构造方法(constructor),用于对象的初始化。构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。构造器的名称应与类的名称一致。Java 通过 new 关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。

声明格式:

[修饰符] 类名(形参列表){
    //n条语句
}

要点:

  1. 通过 new 关键字调用!!
  2. 构造器虽然有返回值,但是不能定义返回值类型(返回值类型肯定是本类),不能在构造器里使用return 返回某个值。
  3. 如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数。如果已定义则编译器不会自动添加!
  4. 构造器的方法名必须和类名一致!

4.6 构造方法的重载

构造方法也是方法,只不过有特殊的作用而已。与普通方法一样,构造方法也可以重载。

【示例4-6】构造方法重载(创建不同用户对象)

public class User {
    int id; // id
    String name; // 账户名
    String pwd; // 密码
    public User() {
 
    }
    public User(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
    public static void main(String[] args) {
        User u1 = new User();
        User u2 = new User(101, "高小七");
        User u3 = new User(100, "高淇", "123456");     
    }
}

雷区:

如果方法构造中形参名与属性名相同时,需要使用this 关键字区分属性与形参。this.id 表示属性id;id 表示 形参 id

4.7 垃圾回收机制(Garbage Collection)

Java 引入了垃圾回收机制,令 c++ 程序员最头痛的内存管理问题迎刃而解。Java 程序员可以将更多的精力放到业务逻辑上而不是内存管理工作上,大大的提高了开发效率。

4.7.1 垃圾回收原理和算法

  • 内存管理

Java 的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放。

对象空间的分配:使用 new关键字创建对象即可。垃圾回收器将负责回收所有“不可达”对象的内存空间。

  • 垃圾回收过程

任何一种垃圾回收算法一般要做两件基本事情:

  1. 发现无用对象
  2. 回收无用对象占用的内存空间。

垃圾回收机制保证可以将“无用的对象”进行回收。无用的对象指的是没有任何变量引用该对象。Java 的垃圾回收器通过相关算法发现无用对象,并进行清除和整理。

  • 垃圾回收相算法
  1. 引用计数法

堆中每个对象都有一个引用计数。被引用一次,计数加1 被引用变量变为 null ,则计数减1,直到计数为 0,则表示变成无用对象。优点是算法简单,缺点是“循环引用的无用对象”无法识别 。

【示例4-7】循环引用示例

public class Student {
    String name;
    Student friend;
     
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();
         
        s1.friend = s2;
        s2.friend = s1;        
        s1 = null;
        s2 = null;
    }
}

s1 和 s2 互相引用对方,导致他们引用计数不为0,但是实际已经无用,但无法被识别。

  1. 引用可达法(根搜索算法)

程序把所有的引用关系看作一张图,从一个节点 GC ROOT 开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。

4.7.2 通用的分代垃圾回收机制

分代垃圾回收机制,是基于这样一个事实:不同的对象的声明周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,一遍提高回收效率。我们将对象分为三种状态:年轻代、年老代、持久代。JVM 将堆内存划分为 Eden、Survivor 和 Tenured/Old 空间。

  1. 年轻代

所有新生成的对象首先都是放在 Eden 区。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,对应的是 Minor GC,每次Minor GC 会清理年轻代的内存,算法采用效率较高的复制算法,频繁的操作,但是会浪费内存空间。当“年轻代”区域存放满对象后,就将对象放到年老代区域。

  1. 年老代

在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期比较长的对象。年老代对象越来越多,我们就需要启动 Major GC 和 Full GC(全量回收),来一次大扫除,全面清理年轻代区域和年老代区域。

  1. 持久代

用于存放静态文件,如Java 类、方法等。持久代对垃圾回收没有显著影响。

在这里插入图片描述

  • Minor GC

用于清理年轻代区域。Eden 区满了就会触发一次Minor GC。清理无用对象,将有用对象复制到 “Survivor1”、“Survivor2” 区中(这两个区,大小空间也想通,同一时刻Survivor1和Survivor2 只有一个在用,一个为空)

  • Major GC

用于清理年老代、年老代区域。成本较高,会对系统性能产生影响。

垃圾回收的过程:

  1. 新创建对象,绝大多数都会存储在 Eden 中,
  2. 当Eden 满了(达到一定比例)不能创建新对象,则触发垃圾回收(GC),将无用对象清理掉,然后剩余对象复制到某个Survivor中,如 S1,同时清空 Eden 区。
  3. 当Eden 区再次满了,会将S1 中的不能清空对象存到另外一个 Survivor 中 ,如S2,同时将Eden 区中的不能清空的对象,也复制到 S1 中,保证 Eden 和 S1,均被清空。
  4. 重复多次(默认15次)Survivor 中没有被清理的对象,则会复制到老年代Old(Tenured)区中,当Old区满了,则会触发一个一次完整的垃圾回收(FullGC),之前新生代的垃圾回收称为(minorGC)

4.7.3 JVM 调优和 Full GC

在对JVM 调优的过程中,很大一部分工作就是对于 Full GC 的调节。有如下原因可能导致 Full GC:

  1. 年老代(Tenured)被写满
  2. 持久代(Perm)被写满
  3. System.gc() 被显式调用(程序建议GC启动,不是调用GC)
  4. 上一次GC之后 Heap 的各个域分配策略动态变化

4.7.4 开发中容易造成内存泄漏的操作

建议:

在实际开发中,经常会造成系统的崩溃。如下这些操作我们应该注意这些使用场景。

如下四种情况时做容易造成内存泄漏的场景,请大家开发时一定注意:

  • 创建大量无用对象

比如,我们在需要大量拼接字符串时,使用了String而不是 StringBuilder。

String str = "";
for (int i = 0; i < 10000; i++) {   
    str += i;     //相当于产生了10000个String对象
}
  • 静态集合类的使用

向HashMap、Vector、List 等的使用最容易出现内存泄漏,这些静态变量的生命周期和应用程序一致,所有对象Object 也不能被释放。

  • 各种连接对象(IO流对象、数据库连接对象、网络连接对象)未关闭

IO流对象、数据库连接对象、网络连接对象等连接对象属于物理连接,和硬盘或者网络连接,不使用的使用后一定要关闭。

  • 监听器的使用

释放对象时,没有删除相应的监听器。

要点:

  1. 程序员无权调用垃圾回收器。
  2. 程序员可以调用 System.gc(),该方法只是通知 JVM,并不是运行垃圾回收器。尽量少用,会申请启动 Full GC,成本高,影响系统性能。
  3. finalize 方法,是Java 提供给程序员同来释放对象或资源的方法,但是尽量少用。

4.8 this 关键字

对象创建的过程和this 的本质

构造方法是创建Java 对象的重要途径,通过new关键字调用构造器时,构造器也确实返回该类的对象,但这个对象并不是完全由构造器负责创建。创建一个对象分为以下四步:

  1. 分配对象空间,并将对象成员变量初始化为0或空
  2. 执行属性值的显式初始化
  3. 执行构造方法
  4. 返回对象的地址给相关的变量

this 的本质就是“创建好的对象的地址”!由于在构造方法调用之前,对象已经创建。因此,在构造方法中也可以使用 this 代表“当前对象”。

this 最常见的使用:

  1. 在程序中产生二义性之处,应使用 this 来指明当前对象;普通方法中,this 总是指向调用方法的对象。构造方法中,this 总是指向正要初始化的对象。
  2. 使用this 关键字重载的构造方法,避免相同的初始化代码。但只能在构造方法中用,并且必须位于构造方法的第一句。
  3. this 不能用于 static 方法中。

【示例4-8】this 代表 “当前对象” 示例

public class User {
    int id;        //id
    String name;   //账户名
    String pwd;   //密码
 
    public User() {
    }
    public User(int id, String name) {
        System.out.println("正在初始化已经创建好的对象:"+this);
        this.id = id;   //不写this,无法区分局部变量id和成员变量id
        this.name = name;
    }
    public void login(){
        System.out.println(this.name+",要登录!");  //不写this效果一样
    }  
     
    public static void main(String[] args) {
        User  u3 = new User(101,"高小七");
        System.out.println("打印高小七对象:"+u3);
        u3.login();
    }
}

在这里插入图片描述

【示例4-9】 this() 调用重载构造方法

public class TestThis {
    int a, b, c;
 
    TestThis() {
        System.out.println("正要初始化一个Hello对象");
    }
    TestThis(int a, int b) {
        // TestThis(); //这样是无法调用构造方法的!
        this(); // 调用无参的构造方法,并且必须位于第一行!
        a = a;// 这里都是指的局部变量而不是成员变量
// 这样就区分了成员变量和局部变量. 这种情况占了this使用情况大多数!
        this.a = a;
        this.b = b;
    }
    TestThis(int a, int b, int c) {
        this(a, b); // 调用带参的构造方法,并且必须位于第一行!
        this.c = c;
    }
 
    void sing() {
    }
    void eat() {
        this.sing(); // 调用本类中的sing();
        System.out.println("你妈妈喊你回家吃饭!");
    }
 
    public static void main(String[] args) {
        TestThis hi = new TestThis(2, 3);
        hi.eat();
    }
}

4.9 static 关键字

在类中,用 static 声明的成员变量为静态成员变量,也称为类变量。类变量的生命周期和类相同,在整个应用程序执行期间都有效。它有如下特点:

  1. 为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化。
  2. 对于该类的所有对象来说,static 成员变量只有一份。被高磊的所有对象共享!!
  3. 一般用 “类名.类属性/方法”来调用(也可以通过对象引用或类名(不需要实例化)访问静态成员)
  4. 在static 方法中不可直接访问非 static 的成员。

核心要点:

static 修饰的成员变量和方法,从属于类。
普通变量和方法从属于对象的。

【示例4-10】static 关键字的使用

/**
 * 测试static关键字的用法
 * @author 高淇
 *
 */
public class User2 {
    int id; // id
    String name; // 账户名
    String pwd; // 密码
     
    static String company = "北京尚学堂"; // 公司名称
     
     
    public User2(int id, String name) {
        this.id = id;
        this.name = name;
    }
     
    public void login() {
        printCompany();
        System.out.println(company); 
        System.out.println("登录:" + name);
    }
     
    public static void printCompany() {
//         login();//调用非静态成员,编译就会报错
        System.out.println(company);
    }
     
    public static void main(String[] args) {
        User2 u = new User2(101, "高小七");
        User2.printCompany();
        User2.company = "北京阿里爷爷";
        User2.printCompany();
    }
}

在这里插入图片描述

在这里插入图片描述

4.10 静态初始化块

构造方法用于对象的初始化!静态初始化块,用于类的初始化操作!静态初始化块中不能直接访问非 static 成员。

注意事项:

静态初始化块执行顺序(学完继承在看这里):

  1. 上溯到Object 类,先执行 Object 的静态初始化块,在向下执行子类的静态初始化块,直到我们的类的静态初始化块为止。
  2. 构造方法执行顺序和上面顺序一样!!

【示例4-11】 static 初始化块

public class User3 {
    int id;        //id
    String name;   //账户名
    String pwd;   //密码
    static String company; //公司名称
    static {
        System.out.println("执行类的初始化工作");
        company = "北京尚学堂";
        printCompany();
    }  
    public static void printCompany(){
        System.out.println(company);
    }  
    public static void main(String[] args) {
        User3  u3 = new User3();
    }
}

在这里插入图片描述

4.11 参数传值机制

Java 中,方法中所有参数都是“值传递”,也就是“传递的是值的副本”。也就是说,我们得到的是 原参数的复印件,而不是原件。因此,复印件改变不会影响原件。

基本数据类型参数的传值

传递的是值的副本。副本改变不会影响原件。

引用类型参数传值

传递的是值的副本。但是引用类型指的是 “对象的地址”。因此,副本和原参数都指向了同一个“地址”,改变 副本指向地址独享的值,也意味着原参数指向对象的值也发生了改变。

【示例4-12】多个变量指向同一个对象

/**
 * 测试参数传值机制
 * @author 高淇
 *
 */
public class User4 {
    int id;        //id
    String name;   //账户名
    String pwd;   //密码
       
    public User4(int id, String name) {
        this.id = id;
        this.name = name;
    }
      
    public   void   testParameterTransfer01(User4  u){
        u.name="高小八";
    }
     
    public   void   testParameterTransfer02(User4  u){
        u  =  new  User4(200,"高三");
    }
      
    public static void main(String[] args) {
        User4   u1  =  new User4(100, "高小七");
         
        u1.testParameterTransfer01(u1); 
        System.out.println(u1.name);
 
        u1.testParameterTransfer02(u1);
        System.out.println(u1.name);
    }
}

在这里插入图片描述

4.12 包

包机制是Java 中管理类的重要手段。开发中,我们会遇到大量同名的类,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理。包对于类的有效管理。包对于类,相当于文件夹对于文件的作用。

4.13 package

我们通过 package 实现对类的管理,package 的使用有两个要点:

  1. 通常是类的第一句非注释语句。
  2. 包名:域名倒着写,再加上模块名,便于内部管理类。

【示例4-13】package 的命名举例

com.sun.test;
com.oracle.test;
cn.sxt.gao.test;
cn.sxt.gao.view;
cn.sxt.gao.view.model;

注意事项:

  1. 写项目时都要加包,不要使用默认包。
  2. com.gao 和 com.gao.car,这两个包没有包含关系,是两个完全独立的包。只是逻辑上看起来后者是前者的一部分。

【示例4-14】 package 的使用

package cn.sxt;
public class Test {
    public static void main(String[] args) {
        System.out.println("helloworld");
    }
}
  • 在eclipse项目中新建包

在src 目录上单击右键,选择 new -> package

在这里插入图片描述

在package 窗口上输入包名即可

在这里插入图片描述
接下来,我们就可以在包上单击右键,新建类!

4.13.1 JDK 中主要的包

Java中的常用包说明
java.lang包含一些Java语言的核心类,如String、Math、Integer、System 和 Thread,提供常用功能
java.awt包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和端丽应用程序的图形用户界面(GUI)
java.net包含执行与网络相关的操作的类。
java.io包含能提供各种输入/输出功能的类
java.util包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。

4.13.2 导入类 import

如果我们要使用其他包的类,需要使用 import 导入,从而可以在本类中直接通过类名来调用,否则就需要书写类的完整包名和类名。import 后,便于编写代码,提高可维护性。

注意要点:

  1. Java 会默认导入 java.lang 包下的所有类,因此这些类我们可以直接使用。
  2. 如果导入两个同名的类,只能用包名+类名来显示调用相关类:

import java.sql.Date;
import java.util.*;//导入该包下所有的类。会降低编译速度,但不会降低运行速度。
 
public class Test{
    public static void main(String[] args) {
        //这里指的是java.sql.Date
        Date now; 
        //java.util.Date因为和java.sql.Date类同名,需要完整路径
        java.util.Date  now2 = new java.util.Date();
        System.out.println(now2);      
        //java.util包的非同名类不需要完整路径
        Scanner input = new Scanner(System.in);    
    }
}

4.13.3 静态导入

静态导入(static import)是在IDK1.5新增加的功能,其作用是用于导入指定类的静态属性,这样我们可以直接使用静态属性。

【示例4-16】 静态导入的使用

package cn.sxt;
 //以下两种静态导入的方式二选一即可
import static java.lang.Math.*;//导入Math类的所有静态属性
import static java.lang.Math.PI;//导入Math类的PI属性
 
public class Test2{
    public static void main(String [] args){
        System.out.println(PI);
        System.out.println(random());
    }
}

在这里插入图片描述

总结

  1. 面向对象可以帮助我们从宏观上把握、从整体上分析整个系统。但是具体到实现部分的微观操作(就是一个个方法),仍然需要面向过程的思路去处理。
  2. 类可以看成一类对象的模板,对象可以看成该类一个具体实例。
  3. 对于一个类来说,一般有三种常见的成员:属性 field、方法 method、构造器 constructor。
  4. 构造器也叫构造方法,用于对象的初始化。构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。构造器的名称应与类的名称一致。
  5. Java 引入了垃圾回收机制,令C++程序员做头疼的内存管理问题迎刃而解。Java程序员可将更多精力放到业务逻辑上而不是内存管理工作,大大提高开发效率。
  6. this 的本质就是“创建好的对象的地址”!this不嗯能够用于 static 方法中。
  7. 在类中,用static 声明的成员变量为静态成员变量,也称为类变量。类变量的生命周期和类相同,在整个应用程序执行期间都有效。在static方法中不可直接访问非 static 的成员。
  8. Java 方法中所有单数都是“值传递”,也就是 “传递的是值的副本”。也就是说,我们得到的是“原参数的复印件,而不是原件”,因此,复印件改变不会影响原件。
  9. 通过package实现对类的管理;如果我们要使用其他包的类,需要使用import 导入,从而可以在本类中直接通过类名来调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值