【JavaSE 第八天】

【JavaSE 第八天】

一、 方法重载

1. 需求

计算器的类中已经有方法:做两个 int 类型的加法

public int add(int a,int b)

想要增加新的方法:做两个 double 类型的加法

public double add(double a,double b)

为了满足更多使用情况,还想有更多方法:

public int add(int a, int b, int c)

小结:在一个类中,很可能有很多类似的需求,为了满足这种需求,会声明很多相似的方法,为了更容易找到并使用,这些功能相近的方法最好使用同一个方法名

2. 前提

  1. 同一个类中
  2. 同名的方法

3. 方法重载的好处

  • 让方法调用者,在调用方法的时候,不必为了相似的功能而查阅文档,查找各种不同的方法名,降低学习成本,提高开发效率。
  • 在调用一系列重载的方法时,感觉上就像是在调用同一个方法。对使用者来说,只需要知道一个方法名就能够应对各种不同情况。

4. 规则限制

限制的来源:本质上只要让系统能够区分清楚我们具体要调用哪一个方法。

  1. 在同一个类中,如果两个方法的方法名一致,那么参数列表必须不同。
  2. 参数列表区分:参数个数和参数类型(二选一不同 或 都不同)(参数类型相同,但顺序不同也可以算重载)
  3. 不能根据返回值类型判断(不看返回值)

5. 重载方法举例

  1. 参数个数不同
public int add(int a, int b)
public int add(int a, int b, int c)
  1. 参数类型不同
public int add(int a, int b)
public double add(double a, double b)

或者

public double add(int a, double b)
public double add(double a, int b)

二、 方法可变参数

1. 需求

在实际开发过程中,确实有一些情况不确定在调用方法时传入几个参数。所以为了让调用方法时能够弹性传参,JavaSE 5.0(JDK 1.5)标准增加了可变参数功能。

2. 语法

    // 能够计算任意个数整数之间的加法
    // 使用 int ... args 来声明可变参数
    public int add(int ...args){
        int sum=0;
        // 在方法体内,可变参数按照数组形式来处理
        for (int i = 0; i < args.length; i++) {
            sum=sum+args[i];
        }
        return sum;
    }

之后正常调用…

3. 语法规则

(1)声明格式:方法名(参数的类型名 ...参数名)
(2)可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个,多个
(3)可变个数形参的方法与同名方法之间,彼此构成重载
(4)可变参数方法的使用与方法参数部分使用数组是一致的
(5)方法的参数部分有可变参数,需要放在形参声明的最后
(6)在一个方法的形参位置,最多只能声明一个可变个数形参
(7)可以将数组传递给可变参数列表
(8)数组作为参数时,不能将多个值传递给数组(解释:数组传递是地址值的传递)(可变参数可以兼容数组参数,但数组参数无法兼容可变参数。当试图使用数组作为参数去实现重载时,会报错,说明可变参数与数组冲突)
(9)方法名相同,一个参数是可变参数,一个参数是一维数组,这两个方法不是重载,因为一个可变参数等价于相应类型的一维数组,就可以对可变参数列表,进行相应的数组操作,比如求长度
(10)可变参数列表所在的方法,是最后被执行访问的

  • 可变参数必须在整个参数列表的最后
    其后不能再有参数列表,否则编译不通过
    不能有多个可变参数(括号中只能有一个可变参数)
  • 当调用方法时实际传入的参数既匹配可变参数列表方法,又匹配一个具体的参数列表方法,那么系统会优先调用具体的参数列表方法
    举例:调用方法 add(5, 3)
    可变参数方法:add(int ... args)
    具体参数方法:add(int i, int j)【系统会调用这个方法】

三、 方法参数的值传递机制

Java 的实参值如何传入方法
Java 里方法的参数传递方式只有一种:值传递。即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。

  • 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
  • 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参

1. 基本数据类型

  • 内存分析:
    基本数据类型

2. 引用数据类型

  • 内存分析:
    引用数据类型。

四、 递归

1. 概念

递归方法:一个方法体内调用它自身慎重使用

  • 方法递归包含了一种隐式的循环,他会重复执行某段代码,但这种重复执行无需循环控制
  • 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环
    使用递归想要达到的目的是让方法中的代码重复执行,而且往往是在上一次执行的结果的基础上,再进一步执行。

2. 代码示例

(1) 计算 1 ~ N 的和
public class MethodRecursion {
    // 计算 1~N 之间的总和
    // 不使用递归
    public int sumOperation(int number){
        int sum=0;
        for(int i=1;i<=number;i++){
            sum=sum+i;
        }
        return sum;
    }
    // 使用递归
    public  int sumOperationRecursion(int number){
        if(number==1){
            return 1;
        }else{
            return number+sumOperationRecursion(number-1);
        }
    }
}
  • 测试程序:
public class MethodRecursionTest {
    public static void main(String[] args) {
        MethodRecursion recursion=new MethodRecursion();
        int sum01=recursion.sumOperation(5);
        System.out.println("sum01 = " + sum01);
        int sum02= recursion.sumOperationRecursion(5);
        System.out.println("sum02 = " + sum02);
    }
}
(2) 没有退出机制的递归调用
    // 一个简单的死循环递归,没有退出机制
    public void recursionToDie(){
        recursionToDie();
    }
  • 此时抛出栈溢出的错误

  • 内存分析:
    没有退出机制的递归

  • 内存耗尽的原因:方法每一次开始执行时都会向系统申请栈内存中的一块空间用来存放局部变量。方法结束时释放这块空间。而没有退出机制的递归调用会不断申请新空间,而完全不释放。

    1. 栈:stack
    2. 堆:heap
(3) 用递归实现阶乘
    // 声明一个实现阶乘的方法
    public int factorial(int i){
        if(i==1){
            return 1;
        }else{
            return i*factorial(i-1);
        }
    }

五、 封装和隐藏

1. 含义

将对象中的数据或代码逻辑隐藏起来,对数据的操作在类的内部完成,对外界隐藏实现的细节。

  1. (为什么需要封装?封装的作用与含义? 例如:使用洗衣机,只需要正常使用即可,没有必要详细了解洗衣机的内部结构,内部电机。)
    我们的程序设计追求“高内聚,低耦合”。
    • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉
    • 低耦合:仅对外部暴露少量的方法用于使用
  2. 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性,可维护性。(把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。)

2. 好处

  • 对象(或组件)内部代码实现的细节可以对外隐藏
  • 简化外部使用对象时的操作难度。外部使用对象时,调用对象暴露出来的方法即可。
  • 让整个系统的开发组件化、模块化程度更高,更有利于实现:高内聚、低耦合。
    (否则会有常见问题:使用者对类内部定义的属性(对象的成员变量)的直接操作会导致数据的错误、混乱或安全性问题。)

3. 做法:信息的封装和隐藏

Java 中通过将数据声明为私有的(private),再提供公共的(public)方法:getXxx()setXxx() 实现对该属性的操作,以实现下述目的:

  • 隐藏一个类中不需要对外提供的实现细节
  • 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作
  • 便于修改,增强的代码的可维护性

4. 示例:

public class MaryObject {
    // 将属性的权限修饰符为私有,不允许外部直接访问
    private int age;
    // 对外暴露的获取数据的getXxx()方法
    public int getAge(){
        return age;
    }
    // 对外暴露设置数据的setXxx()的方法
    public void setAge(int ageOuter){
        // 在方法内部,根据内部的逻辑,对外界数据进行修正
        if(ageOuter<20){
            age=20;
        } else if(ageOuter>60){
            age=60;
        }else{
            age=ageOuter;
        }
    }
}

5. 权限修饰符

修饰符名称含义本类同包其他类子类同工程其他类
private私有可以使用不可使用不可使用不可使用
default缺省可以使用可以使用不可使用不可使用
protected受保护可以使用可以使用可以使用不可使用
public公共可以使用可以使用可以使用可以使用

对于 class 的权限修饰符只可以用 public 和 default (缺省)

  • public 类可以在任意地方被访问(开发中实际使用的方式)
  • default 类只可以被同一个包内部的类访问(实际开发中并不会使用)

六、 构造器(构造方法)

构造器方法 是两码事,不要相互联系。

1. 构造器的引入

当我们使用 new 关键字创建一个类的对象时,就是在使用这个类的构造器了。
如果我们没有明确声明构造器,那么系统会给类分配一个隐式的构造器。(一但自己显式定义构造器后,默认的就不存在了

构造器
构造器的特征

  1. 它具有与类相同的名称。
  2. 它不声明返回值类型。(与声明 void 不同)
  3. 它不能被 static ,final ,synchronized ,abstract ,native 修饰,不能有 return 语句返回值。

2. 构造器的作用

构造器的名字和类的名字是一样的。(同名)

  • 作用一:创建对象
  • 作用二:在创建对象的过程中,对类进行初始化操作。这些操作写在构造器的大括号中。(初始化操作放到构造器里面,由构造器自动完成,程序员就不必在创建对象后还想着对这对象做初始化操作。

3. 构造器的组成部分

构造器的组成部分
语法格式:

修饰符 类名(参数列表){
    初始化语句;
}

4. 构造器的参数

根据参数的不同,构造器可以分为两类:

  1. 隐式无参构造器(系统默认提供)
  2. 显式定义一个或多个构造器(无参、有参)
(1) 有一个参数构造器 示例:
public class Soldier {
    private String soldierName;
    public Soldier(String soldierName) {
        this.soldierName = soldierName;
    }
}

注意:当类中声明了有参数的构造器之后,系统将不再给这个类分配无参的构造器。

(2) 一个类可以有多个构造器
  • 根据参数列表的不同,多个构造器之间是重载的关系。(规则和方法重载一致:Ⅰ、要么参数个数不同 Ⅱ、要么参数类型不同)
  • 构造器中还可以写其他代码,方法中可以写的,基本上全部都可以写进构造器中。
public class Soldier {
    private String soldierName;
    private int age;
    private String weapon;
    private String gender;
    public Soldier(){
        // 无参数的构造器
    }
    public Soldier(int age){
        this.age=age;
    }
    public Soldier(String soliderName){
        // 一个参数的构造器
        this.soldierName=soliderName;
    }
    public Soldier(String soldierName,String weapon){
        // 两个参数的构造器
        this.soldierName=soldierName;
        this.weapon=weapon;
    }
    public Soldier(String soldierName,String weapon,String gender){
        // 三个参数的构造器
        this.soldierName=soldierName;
        this.weapon=weapon;
        this.gender=gender;
    }
    public Soldier(int age,String soldierName,String weapon,String gender){
        // 四个参数的构造器
        this.age=age;
        this.soldierName=soldierName;
        this.weapon=weapon;
        this.gender=gender;
    }
}

5. 构造器相关语法规则

  • Java 语言中,每个类都至少有一个构造器
  • 默认构造器的修饰符与所属类的修饰符一致
  • 一旦显式定义了构造器,则系统不再提供默认构造器
  • 一个类可以创建多个重载的构造器
  • 父类的构造器不可被子类继承

6. 构造器相关的快捷键

(1) 唤出快捷菜单
  • Alt (+ Fn)+ Insert
    弹出快捷菜单
    弹出快捷菜单
(2) 声明无参构造器
  • 回车后弹出复选项框
    声明无参构造器
(3) 声明全部参数构造器

声明全部参数构造器

(4) 在快捷菜单输入字符匹配菜单项

在快捷菜单输入字符匹配菜单项

(5) 生成 getter()setter() 方法
  • 通常针对所有属性生成 getter()setter() 方法:
  • 继续进行 Ctrl + A 全选所有属性 再 回车 生成 getter()setter() 方法
(6) 生成 toString() 方法
  • 方法类似与’生成 getter 和 setter 方法’:
    (复选框菜单 默认全选所有属性,直接 回车)

7. 总结:类的属性赋值的顺序

很多位置都可以对类的属性赋值,总结其赋值的顺序:

  • 默认的位置:
    1. 默认初始化
    2. 显式初始化
    3. 构造器中初始化
    4. 通过 “ 对象.属性 ” 或 “ 对象.方法 ” 的方式赋值
  • 赋值的先后顺序:
    1 ——> 2 ——> 3 ——> 4
  1. 系统根据这个属性的类型来设置默认值。
private int age;
  1. 显示初始化
private int age = 6;
  1. 构造器初始化
public Person(int age) {
    this.age = age;
}
  1. 调用方法或直接给属性赋值
person.setAge(5);   //设置为 private(私有的)无法直接访问时
// 或者
person.age = 18;    // 不是 private(私有的)可以直接访问时,直接更改属性值

七、 JavaBean

1. 含义:

  • JavaBean 是一种 Java 语言写成的可重用的组件
  • 所谓 JavaBean 是指符合如下标准的 Java 类:
    1. 类是公共的
    2. 有一个无参的公共的构造器
    3. 有属性值,且有对应的 get 、set 方法
  • 用户可以使用 JavaBean 将功能、处理、值、数据库访问和其他任何可以用 Java 代码创造的对象进行打包,并且是其他的开发者可以通过内部的 JSP 页面、Servlet、其他 JavaBean、applet 程序或者应用来使用这些对象。用户可以认为 JavaBean 提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。

2. 实际开发项目中用到的类

  1. JavaBean(主要用来封装数据)
    • 用来描述现实世界中的具体数据:Book、Employee、Department、Product、……
    • 它也有其他名称:domain(领域模型)、POJO(Plain old Java Object 普通的传统的 Java 对象)、entity(实体类)
  2. 功能性组件:用来执行具体代码逻辑对应的操作(主要进行操作)
    • BookServlet
    • BookService
    • BookDao
  3. 工具类:通常用来把某个特定操作封装到工具方法中。工具类通常是用类名来直接调用方法。(我们平常写的就需要用对象调用方法,而工具类就可以使用类名来直接调用(因为它的方法前面加上了 static ))
    • Aarrys.sort()

3. JavaBean 的要求

必须有的组成部分:

  • 私有的属性
  • 针对私有属性设置的公共的 getter()setter() 方法
  • 无参的构造器

4. getter()setter() 方法的规则

属性声明:

private int age;

getter()setter() 方法:

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

规则描述如下:

  • getXxx()setXxx() 方法 取出方法名字符串 (如:getAge)
  • 去掉 get 或 set(剩下Xxx) (如:Age)
  • Xxx 首字母小写 (如:Age 变为 age)

5. UML 类图介绍

UML来图介绍

6. IDEA 生成 UML 图

  • 选中代码中类名,进行 ①鼠标右击类名 选中 ② Diagrams(图)——③ Show Diagrams(显示图)
  • 显示图后: 最开始只显示类的信息 有选项(Fields 属性)(Methods 方法)(Constructors 构造器)(Properties)(Inner Classes 内部类)
  • 这种 UML 图之后还就可以用来查看 继承、接口 等内容

八、 this 关键字

1. 含义

  1. 在 Java 中,this 关键字,它的作用和其词义很接近:
    • 它在方法内部使用,即这个方法所属的对象的引用
    • 它在构造器内部使用,表示该构造器正在初始化的对象
  2. this 可以调用类的①属性、②方法和③构造器
  3. 使用 this 关键字
    • 当在方法内需要用到调用该方法的对象时,就用 this 。具体的:我们使用 this 来区分属性和局部变量
    • 类的方法中:代表调用当前方法的对象
      类的方法中this
  • 类的构造器中:代表当前构造器正在创建的对象
    类的构造器中this

2. this 的作用

(1) 调用属性
System.out.println("我的年龄:" + this.age);
(2) 调用方法
System.out.println("我的性别:" + this.getGender());
(3) 调用构造器

在类中的某个构造器中调用这个类的其他构造器:

public class Tiger {
    private String tigerName;
    private int tigerAge;
    public Tiger(){
        System.out.println("这里是Tiger类的无参构造器");
    }
    public Tiger(String tigerName) {
        this();
        this.tigerName = tigerName;
        System.out.println("这是Tiger类的一个参数的构造器");
    }
    public Tiger(String tigerName, int tigerAge) {
        this("haha"); // 这句话必须在构造器的第一行
        this.tigerName = tigerName;
        this.tigerAge = tigerAge;
        System.out.println("这是Tiger类的两个参数的构造器");
    }
}

(4) this 调用构造器的规则
  • 可以在类的构造器中使用 “ this (参数列表) ” 的方式,调用本类中重载的其他构造器
  • 在构造器中调用其他构造器,this (无/参数列表) 语句必须在第一行
  • 明确:构造器中不能通过 “ this (参数列表) ” 的方式调用自身构造器
  • 如果一个类中声明了 n 个构造器,则最多有 n - 1 个构造器中使用了 “ this(参数列表)
  • 在类的一个构造器中,最多只能声明一个 “ this (参数列表)
  • 各个构造器之间调用不能形成闭环,否则会造成死循环,无法跳出
    循环调用逻辑如下:(陷入死循环,不允许)
    循环调用逻辑

九、 package 关键字

用来声明当前类所在的包。package 声明所在包的语句必须是在类的第一行。若缺省该语句,则指定为无名包。

格式为:package 顶层包名.子包名;

  • 包对应于文件系统的目录,package 语句中,用 “ . ” 来指明包(目录)的层次
  • 包通常用小写单词标识,通常使用所在公司域名的倒置:com.xxxxxxx.xxx

1. JDK 中主要的包介绍

  1. java.lang 包含一些 Java 语言的核心类,如 String、Math、Integer、System 和 Thread,提供常用功能
  2. java.net 包含执行与网络相关的操作的类和接口
  3. java.io 包含能提供多种输入/输出功能的类
  4. java.util 包含一些实用工具类,如:定义系统特征、接口的集合框架类、使用与日期日历相关的函数
  5. java.text 包含了一些 Java 格式化相关的类
  6. java.sql 包含了 Java 进行 JDBC 数据库编程的相关类/接口
  7. java.awt 包含了构成抽象窗口工具类(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形界面(GUI)。B/S C/S

十、 import 关键字

在 JDK 编译 Java 源程序的时候,并不能保证所有的类都能够被 JDK 默认识别到。JDK 无法默认识别的类就需要我们通过 import 语句导入。
为使用定义在不同包中的 Java 类,需用 import 语句来引入指定包层次所需要的类或全部类(.*)import 语句告诉编译器到哪里去寻找类

语法格式:import 包名.类名
精确导入:在 import 关键字后面指定全类名

import java.util.Scanner;

全部导入:在 import 关键字后面指定包名.*

import java.util.*;

语法规则:

  1. 在源文件中使用 import 显式的导入指定包下的类或接口
  2. 声明在包的声明和类的声明之间
  3. 如果需要导入多个类或接口,那么就并列显式多个 import 语句即可
  4. 举例:可以使用 java.util.* 的方式,一次性导入 util 包下的所有的类或接口
  5. 如果导入的类或接口时 java.lang 包下的,或者是当前包下的,则可以省略此 import 语句
  6. 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的是哪个类
  7. 如果已经导入 java.a 包下的类,那么如果需要使用 a 包的子包下的类的话,仍需要导入
  8. import static 组合的使用,调用指定类或接口下的静态的属性或方法(静态导入。让当前类可以直接调用导入的类中的静态属性或方法,不必写类名。)
// 这里导入了一个Book类
import java.awt.print.Book;
public class ImportTest {
    public static void main(String[] args) {       
        // 但是这里又要使用另外一个Book类
        // 为了区分二者,这里使用全类名来引用
        com.xxxxxxx.object.test.Book book = new com.xxxxxxx.object.test.Book();
    }
    
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值