IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 大数据开发理论基础与项目实战(一)Java SE之4.方法和封装 -> 正文阅读

[Java知识库]大数据开发理论基础与项目实战(一)Java SE之4.方法和封装

前言

本文主要介绍了成员方法和面向对象的特性之一封装,主要包括构造方法、方法重载、this关键字、方法的递归调用和封装,包含了概念基础和应用举例,适合初学者。

1.构造方法

(1)构造方法的概念和应用

格式为:

class 类名 {
  类名(形参列表) {
    构造方法体;
  }
}

构造方法的特点为:

方法名与类名相同;

没有返回值类型,也不需要void类型。

如下:

/*
  构造方法的使用
*/

public class MethodPerson {
  
  String name;
  int age;
  
  // 自定义构造方法
  MethodPerson() {
    System.out.println("执行了自定义的构造方法");
  }
  
  // 自定义成员方法
  void printVariable() {
    System.out.println("我是" + name + ",今年" + age + "岁了");
  }
  
  public static void main(String[] args) {
    
    // 1.声明一个Person类型的引用指向Person类型的对象
    MethodPerson p = new MethodPerson();
    // 2.打印特征
    p.printVariable();
  }
}

输出:

执行了自定义的构造方法
我是null,今年0岁了

可以看到,调用了定义的构造方法Person() ,但是我们之前的例子中都没有定义构造方法,也能正常运行,这是因为当类中没有定义构造方法时,编译器会自动添加无参空构造构造方法,即默认构造方法、缺省构造方法,如Person(){}

若类中提供了构造方法,则编译器不再提供构造方法。

(2)构造方法的作用

如果想要在构建对象的同时,自定义成员变量的初始值,就需要自定义构造方法;

如果需要在创建不同对象的同时,其成员变量的值不同,就可以传递参数。

如下:

/*
  构造方法的使用
*/

public class MethodPerson {
  
  String name;
  int age;
  
  // 自定义构造方法
  MethodPerson(String s, int i) {
    System.out.println("执行了" + s + "的构造方法");
    name = s;
    age = i;
  }
  
  // 无参构造方法
  MethodPerson() {
  }
  
  // 自定义成员方法
  void printVariable() {
    System.out.println("我是" + name + ",今年" + age + "岁了");
  }
  
  public static void main(String[] args) {
    
    // 1.声明一个Person类型的引用指向Person类型的对象
    MethodPerson p1 = new MethodPerson("Corley", 18);
    // 2.打印特征
    p1.printVariable();
    
    MethodPerson p2 = new MethodPerson("Jack", 20);
    // 2.打印特征
    p2.printVariable();
    
    MethodPerson p3 = new MethodPerson();
    // 2.打印特征
    p3.printVariable();
  }
}

输出:

执行了Corley的构造方法
我是Corley,今年18岁了
执行了Jack的构造方法
我是Jack,今年20岁了
我是null,今年0岁了

可以看到,可以同时定义有参和无参的构造方法,便于在创建对象时传递或者不传递参数都可以成功创建对象。

可以总结:

使用new关键字创建对象时会自动 调用构造方法实现成员变量的初始化。

再在Point类中实现构造方法,如下:

/*
  Point类中实现构造方法
*/

public class MethodPoint {
  
  int x;
  int y;
  
  // 自定义无参构造方法
  MethodPoint() {}
  // 自定义有参构造方法
  MethodPoint(int i, int j) {
    x = i;
    y = j;
  }
  
  void show() {
    System.out.println("横坐标是" + x + ",纵坐标是" + y);
  }
  
  public static void main(String[] args) {
    
    // 1.使用无参方式构造对象并打印成员变量
    MethodPoint p1 = new MethodPoint();
    p1.show();
    
    // 2.使用有参方式构造对象并打印成员变量
    MethodPoint p2 = new MethodPoint(12, 20);
    p2.show();
  }
}

输出:

横坐标是0,纵坐标是0
横坐标是12,纵坐标是20

2.方法重载

(1)重载的概念和体现形式

方法名称相同、参数列表不同,则这些方法之间构成重载(Overload) 关系。

示意如下:

/*
  方法重载
*/

public class OverloadTest {
  
  // 自定义构造方法
  void show() {
    System.out.println("Showing...");
  }
  
  void show(int i) {
    System.out.println("Showing " + i);
  }
  
  void show(int i, double d) {
    System.out.println("Showing " + i + " " + d);
  }
  
  void show(int i, int j) {
    System.out.println("Showing " + i + " " + j);
  }
  
  void show(double d, int i) {
    System.out.println("Showing " + i + " " + d);
  }
  
  /*
  void show(double a, int b) {  // 报错,与参数变量名无关
    System.out.println("Showing " + a + " " + b);
  }
  */
  
  /*
  int show(double d, int i) {    // 报错,与返回值类型无关
    System.out.println("Showing " + i + " " + d);
  }
  */
  
  public static void main(String[] args) {
    
    // 1.声明OverloadTest类型的引用指向该类型的对象
    OverloadTest ot = new OverloadTest();
    // 2.调用成员方法
    ot.show();
    ot.show(123);
    ot.show(123, 123.456);
    ot.show(123, 456);
    ot.show(123.456, 123);
  }
}

输出:

Showing...
Showing 123
Showing 123 123.456
Showing 123 456
Showing 123 123.456

方法重载的体现形式总结如下:

  • 方法参数的个数不同

  • 方法参数的类型不同

  • 方法参数的顺序不同

  • 与返回值类型和形参变量名无关

????建议返回值类型相同

判断方法能否构成重载的核心∶

调用方法时能否加以区分

(2)方法重载的简单应用

MethodPerson类中实现方法重载,如下:

/*
  构造方法的使用
*/

public class MethodPerson {
  
  String name;
  int age;
  
  // 自定义构造方法
  MethodPerson(String s, int i) {
    System.out.println("执行了" + s + "的构造方法");
    name = s;
    age = i;
  }
  
  // 无参构造方法
  MethodPerson() {
  }
  
  // 自定义成员方法实现年龄增长1岁
  void grow() {
    age++;
  }
  
  // 自定义成员方法实现年龄增长指定数值
  void grow(int a) {
    age += a;
  }
  
  // 自定义成员方法
  void printVariable() {
    System.out.println("我是" + name + ",今年" + age + "岁了");
  }
  
  public static void main(String[] args) {
    
    // 1.声明一个Person类型的引用指向Person类型的对象
    MethodPerson p1 = new MethodPerson("Corley", 18);
    // 2.打印特征
    p1.printVariable();
    
    MethodPerson p2 = new MethodPerson("Jack", 20);
    p2.printVariable();
    
    MethodPerson p3 = new MethodPerson();
    p3.printVariable();
    
    System.out.println("----------------------------------------------");
    // 3.重载方法的调用和测试
    p2.grow();
    p2.printVariable();
    p2.grow(5);
    p2.printVariable();
  }
}

输出:

执行了Corley的构造方法
我是Corley,今年18岁了
执行了Jack的构造方法
我是Jack,今年20岁了
我是null,今年0岁了
----------------------------------------------
我是Jack,今年21岁了
我是Jack,今年26岁了

MethodPoint类中实现方法重载,如下:

/*
  Point类中实现构造方法
*/

public class MethodPoint {
  
  int x;
  int y;
  
  // 自定义无参构造方法
  MethodPoint() {}
  // 自定义有参构造方法
  MethodPoint(int i, int j) {
    x = i;
    y = j;
  }
  
  void show() {
    System.out.println("横坐标是" + x + ",纵坐标是" + y);
  }
  
  // 实现纵坐标减1
  void down() {
    y--;
  }
  
  // 实现纵坐标减去指定数值
  void down(int dy) {
    y -= dy;
  }
  
  public static void main(String[] args) {
    
    // 1.使用无参方式构造对象并打印成员变量
    MethodPoint p1 = new MethodPoint();
    p1.show();
    
    // 2.使用有参方式构造对象并打印成员变量
    MethodPoint p2 = new MethodPoint(12, 20);
    p2.show();
    
    System.out.println("-----------------------------------");
    // 3.调用重载方法
    p2.down();
    p2.show();
    p2.down(5);
    p2.show();
  }
}

输出:

横坐标是0,纵坐标是0
横坐标是12,纵坐标是20
-----------------------------------
横坐标是12,纵坐标是19
横坐标是12,纵坐标是14

(3)重载的实际意义

方法重载的实际意义在于只需要记住一个方法名就可以调用各种不同的版本、实现不同的功能。

例如对于我们经常用的打印的方法java.io.FilterOutputStream.println() 就实现了方法的重载,所以可以打印各种类型的变量,如下:

方法含义
println()通过写行分隔符字符串来终止当前行。
println?(boolean x)打印一个布尔值,然后终止该行。
println?(char x)打印一个字符,然后终止该行。
println?(char[] x)打印一个字符数组,然后终止该行。
println?(double x)打印一个双,然后终止该行。
println?(float x)打印一个浮点数,然后终止该行。
println?(int x)打印一个整数,然后终止该行。
println?(long x)打印一个长,然后终止该行。
println?(Object x)打印一个对象,然后终止该行。
println?(String x)打印一个字符串,然后终止该行。

方法重载的使用场景:

如果需要定义构造方法,需要使用方法重载;

如果需要定义功能类似、但是参数可能不同的方法,需要使用方法重载。

3.this关键字

(1)this关键字的基本概念

this关键字的含义:

  • 若在构造方法中出现了this关键字,则代表当前正在构造 的对象;

  • 若在成员方法中出现了this关键字,则代表当前正在调用 的对象。

  • this关键字本质上是当前类类型的引用变量

/*
  this关键字的使用
*/

public class ThisTest {
  
  // 自定义构造方法
  ThisTest() {
    System.out.println("构造方法中,this = " + this);
  }
  
  void print() {
    System.out.println("成员方法中,this = " + this);
  }
  
  public static void main(String[] args) {
    
    // 1.声明ThisTest类型的引用指向该类型的对象
    ThisTest tt = new ThisTest();
    System.out.println("main方法中,tt = " + tt);
    // 2.调用print方法
    tt.print();
  }
}

输出:

构造方法中,this = ThisTest@50eac852
main方法中,tt = ThisTest@50eac852
成员方法中,this = ThisTest@50eac852

可以看到,在构造方法中的this所代表的对象和new 得到的对象是同一个对象。

(2)this关键字的工作原理

this关键字是当前类类型的引用,也是构造方法和成员方法中隐含的关键字。

之前在成员方法和构造方法中使用成员变量时,直接使用了成员变量名,与main方法中引用.成员变量名 的形式有所区别,例如System.out.println("我是" + name + ", 年龄是" + age + "岁了");,这是因为隐藏了关键字this,等价于System.out.println("我是" + ``this.name`` + ", 年龄是" + this.age + "岁了"); ,执行效果是相同的。

this关键字的工作原理如下:

在构造方法中和成员方法中访问成员变量时,编译器会加上this的前缀,而this.相当于汉语中"我的" ,当不同的对象调用同一个方法时,由于调用方法的对象不同导致this关键字所代表的对象随之不同,从而this.方式访问的结果也就随之不同。

(3)this关键字的使用方式

Ⅰ 使用方式一

之前在定义成员方法时,一般都是保证形参变量名与成员变量不同。但是为了增加代码的可读性,还是应该让形参变量名与成员变量保持一致。

由于就近原则,当局部变量名与成员变量名相同时,在方法体中会优先使用较近的局部变量(形参变量)、而不是成员变量,若希望使用成员变量,则可以在成员变量的前面加上this前缀,明确声明该变量是成员变量。

MethodPerson类使用this进行修改如下:

/*
  构造方法的使用
*/

public class MethodPerson {
  
  String name;
  int age;
  
  // 自定义构造方法
  MethodPerson(String name, int age) {
    System.out.println("执行了" + name + "的构造方法");
    this.name = name;
    this.age = age;
  }
  
  // 无参构造方法
  MethodPerson() {
  }
  
  // 自定义成员方法实现年龄增长1岁
  void grow() {
    age++;
  }
  
  // 自定义成员方法实现年龄增长指定数值
  void grow(int age) {
    this.age += age;
  }
  
  // 自定义成员方法
  void printVariable() {
    // System.out.println("我是" + name + ",今年" + age + "岁了");
    System.out.println("我是" + this.name + ", 年龄是" + age + "岁了");
  }
  
  public static void main(String[] args) {
    
    // 1.声明一个Person类型的引用指向Person类型的对象
    MethodPerson p1 = new MethodPerson("Corley", 18);
    // 2.打印特征
    p1.printVariable();
    
    MethodPerson p2 = new MethodPerson("Jack", 20);
    p2.printVariable();
    
    MethodPerson p3 = new MethodPerson();
    p3.printVariable();
    
    System.out.println("----------------------------------------------");
    // 3.重载方法的调用和测试
    p2.grow();
    p2.printVariable();
    p2.grow(5);
    p2.printVariable();
  }
}

效果与之前相同。

MethodPoint类也可以进行修改,如下:

/*
  Point类中实现构造方法
*/

public class MethodPoint {
  
  int x;
  int y;
  
  // 自定义无参构造方法
  MethodPoint() {}
  // 自定义有参构造方法
  MethodPoint(int x, int y) {
    this.x = x;
    this.y = y;
  }
  
  void show() {
    System.out.println("横坐标是" + x + ",纵坐标是" + y);
  }
  
  // 实现纵坐标减1
  void down() {
    y--;
  }
  
  // 实现纵坐标减去指定数值
  void down(int y) {
    this.y -= y;
  }
  
  public static void main(String[] args) {
    
    // 1.使用无参方式构造对象并打印成员变量
    MethodPoint p1 = new MethodPoint();
    p1.show();
    
    // 2.使用有参方式构造对象并打印成员变量
    MethodPoint p2 = new MethodPoint(12, 20);
    p2.show();
    
    System.out.println("-----------------------------------");
    // 3.调用重载方法
    p2.down();
    p2.show();
    p2.down(5);
    p2.show();
  }
}

Ⅱ 使用方式二

this关键字除了可以通过this. 的方式调用成员变量和成员方法,还可以作为方法的返回值

/*
  构造方法的使用
*/

public class MethodPerson {
  
  String name;
  int age;
  
  // 自定义构造方法
  MethodPerson(String name, int age) {
    System.out.println("执行了" + name + "的构造方法");
    this.name = name;
    this.age = age;
  }
  
  // 无参构造方法
  MethodPerson() {
  }
  
  // 自定义成员方法实现年龄增长1岁
  void grow() {
    age++;
  }
  
  // 自定义成员方法实现年龄增长指定数值
  void grow(int age) {
    // 调用成员变量
    this.age += age;
  }
  
  // 自定义成员方法获取并返回Person类型对象
  MethodPerson getPerson() {
    // this作为方法的返回值
    return this;
  }
  
  // 自定义成员方法
  void printVariable() {
    // 调用成员方法
    this.grow();
    System.out.println("我是" + this.name + ", 年龄是" + age + "岁了");
  }
  
  public static void main(String[] args) {
    
    // 1.声明一个Person类型的引用指向Person类型的对象
    MethodPerson p1 = new MethodPerson("Corley", 18);
    // 2.打印特征
    p1.printVariable();
    
    MethodPerson p2 = new MethodPerson("Jack", 20);
    p2.printVariable();
    
    MethodPerson p3 = new MethodPerson();
    p3.printVariable();
    
    System.out.println("----------------------------------------------");
    // 3.重载方法的调用和测试
    p2.grow();
    p2.printVariable();
    p2.grow(5);
    p2.printVariable();
    
    System.out.println("----------------------------------------------");
    // 4.调用成员方法获取返回值
    MethodPerson p4 = p1.getPerson();
    System.out.println("p1 = " + p1);
    System.out.println("p4 = " + p4);
  }
}

输出:

执行了Corley的构造方法
我是Corley, 年龄是19岁了
执行了Jack的构造方法
我是Jack, 年龄是21岁了
我是null, 年龄是1岁了
----------------------------------------------
我是Jack, 年龄是23岁了
我是Jack, 年龄是29岁了
----------------------------------------------
p1 = MethodPerson@2a3b5b47
p4 = MethodPerson@2a3b5b47

Ⅲ 使用方式三

构造方法的第一行 可以使用this()的方式来调用本类中的其他构造方法

/*
  this的使用方式3
*/

public class Boy {
  
  String name;
  
  Boy() {
    // 调用本类中的有参构造方法
    this("Jack");
    System.out.println("无参构造方法...");
  }
  
  Boy(String name) {
    System.out.println("有参构造方法...");
    this.name = name;
  }
  
  void print() {
    System.out.println("我的名字是" + name);
  }
  
  public static void main(String[] args) {
    
    // 1.无参方式构建对象
    Boy b1 = new Boy();
    b1.print();
    
    System.out.println("-----------------------------------");
    // 2.有参方式构造对象
    Boy b2 = new Boy("Corley");
    b2.print();
  }
  
}

输出:

有参构造方法...
无参构造方法...
我的名字是Jack
-----------------------------------
有参构造方法...
我的名字是Corley

还可以如下:

/*
  this的使用方式3
*/

public class Boy {
  
  String name;
  
  Boy() {
    // 调用本类中的有参构造方法
    // this("Jack");
    System.out.println("无参构造方法...");
  }
  
  Boy(String name) {
    this();
    System.out.println("有参构造方法...");
    this.name = name;
  }
  
  void print() {
    System.out.println("我的名字是" + name);
  }
  
  public static void main(String[] args) {
    
    // 1.无参方式构建对象
    Boy b1 = new Boy();
    b1.print();
    
    System.out.println("-----------------------------------");
    // 2.有参方式构造对象
    Boy b2 = new Boy("Corley");
    b2.print();
  }
  
}

输出:

无参构造方法...
我的名字是null
-----------------------------------
无参构造方法...
有参构造方法...
我的名字是Corley

但是两个构造方法中不能都调用this() ,因为这样会出现互相调用,即递归调用 ,编译不能通过。

(4)引用类型变量的注意事项

引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象。
当某个引用类型变量为null时无法对对象实施访问,因为它没有指向任何对象。此时,如果通过引用访问成员变量或调用方法,会产生NullPointerException异常。

例如:

/*
  this的使用方式3
*/

public class Boy {
  
  String name;
  
  Boy() {
    // 调用本类中的有参构造方法
    // this("Jack");
    System.out.println("无参构造方法...");
  }
  
  Boy(String name) {
    this();
    System.out.println("有参构造方法...");
    this.name = name;
  }
  
  void print() {
    System.out.println("我的名字是" + name);
  }
  
  public static void main(String[] args) {
    
    // 1.无参方式构建对象
    Boy b1 = new Boy();
    b1.print();
    
    System.out.println("-----------------------------------");
    // 2.有参方式构造对象
    Boy b2 = new Boy("Corley");
    b2.print();
    
    // 3.自定义类型的引用变量为空
    Boy b3 = null;
    b3.print();
  }
  
}

可以正常编译,但是解释执行时会抛出异常Exception in thread "main" java.lang.NullPointerException

声明引用类型的对象时,需要有明确的指向,即不能为空,因为如果为空说明该引用在栈区的内容为空,即没有指向的堆区空间,即该对象没有对应的数据空间,所以在调用方法或者访问成员变量时就会抛出异常。

4.方法递归调用

(1)阶乘的计算

编程实现参数n的阶乘并返回,所谓阶乘就是从1累乘到n的结果。

方式一:

通过for循环实现,即递推方式 。如下:

/*
  计算阶乘
*/

public class FactorialTest {
  
  // 自定义方法计算参数n的阶乘并返回
  int fact(int n) {    
    int res = 1;
    for(int i = 1; i <= n; i++) {
      res *= i;
    }
    return res;
  }
  
  public static void main(String[] args) {
    
    // 1.声明FactorialTest类型的引用指向该类型的对象
    FactorialTest ft = new FactorialTest();
    // 2.调用方法进行计算
    int res = ft.fact(10);
    System.out.println("计算结果是:" + res);
  }
}

输出:

计算结果是:3628800

方式二:

根据阶乘的特点进行分析:

当n的值为1时,则阶乘的结果为1;

当n大于1时,n! = n * (n-1)!

即可以使用递归方式 ,代码如下:

/*
  计算阶乘
*/

public class FactorialTest {
  
  // 自定义方法计算参数n的阶乘并返回
  int fact1(int n) {
    // 递推方式
    int res = 1;
    for(int i = 1; i <= n; i++) {
      res *= i;
    }
    return res;
  }
  
  int fact2(int n) {
    if (1 == n) return 1;
    return n * fact2(n-1);
  }
  
  public static void main(String[] args) {
    
    // 1.声明FactorialTest类型的引用指向该类型的对象
    FactorialTest ft = new FactorialTest();
    // 2.调用方法进行计算
    int res1 = ft.fact1(10);
    System.out.println("递推方式计算结果是:" + res1);
    int res2 = ft.fact2(10);
    System.out.println("递归方式计算结果是:" + res2);
  }
}

输出:

递推方式计算结果是:3628800
递归方式计算结果是:3628800

可以看到,执行结果完全相同,但是递归方式代码更简洁。

(2)递归方式的本质和注意事项

递归的本质是在方法体的内部直接或间接调用当前方法自身

使用递归的注意事项包括:

  • 使用递归必须要有递归的规律和终止条件

  • 使用递归必须使得问题简单化而不是复杂化;

  • 如果递归影响到程序的执行性能,则使用递推代之。

(3)斐波拉契数列的递归实现

编程实现斐波拉契数列中第n项的数值并返回。
斐波拉契数列: 1 1 2 3 5 8 13 21 ……

先用递归方式,进行分析:

如果n为1或者2,结果是1;

否则结果是前两项的和。

实现如下:

/*
  斐波拉契数列的实现
*/

public class FibonacciSequence {
  
  // 1.递归实现斐波拉契数列
  int fib(int n) {
    if(1 == n || 2 == n) return 1;
    return fib(n-1) + fib(n-2);
  }
  
  public static void main(String[] args) {
    
    // 1.声明FibonacciSequence类型的引用指向该类型的引用
    FibonacciSequence fs = new FibonacciSequence();
    int res = fs.fib(10);
    // 2.打印计算结果
    System.out.println("计算结果是:" + res);
  }
}

输出:

计算结果是:55

分析递归的过程可以发现,这种方式实现斐波拉契数列的性能较低,如果n较大时就会运行很长时间,因为拆数和调用重复方法的次数较多,出现了大量计算(包括重复计算)。

现使用递推方式实现,如下:

/*
  斐波拉契数列的实现
*/

public class FibonacciSequence {
  
  // 1.递归实现斐波拉契数列
  int fib1(int n) {
    if(1 == n || 2 == n) return 1;
    return fib1(n-1) + fib1(n-2);
  }
  
  // 2.递推实现斐波拉契数列
  int fib2(int n) {
    int x = 1;
    int y = 1;
    for(int i = 3; i <= n; i++) {
      int z = x + y;
      x = y;
      y = z;
    }
    return y;
  }
  
  public static void main(String[] args) {
    
    // 1.声明FibonacciSequence类型的引用指向该类型的引用
    FibonacciSequence fs = new FibonacciSequence();
    // 2.调用方式计算并打印计算结果
    int res1 = fs.fib1(10);
    System.out.println("递归计算结果是:" + res1);
    int res2 = fs.fib2(10);
    System.out.println("递推计算结果是:" + res2);
  }
}

输出:

递归计算结果是:55
递推计算结果是:55

5.封装

(1)代码的拆分实现

在开发中,不建议将成员方法和main方法放在同一个类中,因为main方法不是这个类独有的,这样会显得代码结构不够明确、清晰,应该在实现功能时创建功能类 ,在这个类中只放这个类的成员变量和成员方法,而将main方法放到测试类 (类名一般以Test结尾)中,即将代码实现物理上的拆分 、结构更清晰、可维护性更高,同时可以实现代码的复用

以上面的FibonacciSequence 类为例,进行拆分,功能类FibonacciSequence.java如下:

/*
  斐波拉契数列的实现 功能类
*/

public class FibonacciSequence {
  
  // 1.递归实现斐波拉契数列
  int fib1(int n) {
    if(1 == n || 2 == n) return 1;
    return fib1(n-1) + fib1(n-2);
  }
  
  // 2.递推实现斐波拉契数列
  int fib2(int n) {
    int x = 1;
    int y = 1;
    for(int i = 3; i <= n; i++) {
      int z = x + y;
      x = y;
      y = z;
    }
    return y;
  }
  
  
}

测试类FibonacciSequenceTest.java如下:

/*
  实现对斐波拉契类的测试 测试类
*/

public class FibonacciSequenceTest {
  
  public static void main(String[] args) {
    
    // 1.声明FibonacciSequence类型的引用指向该类型的引用
    FibonacciSequence fs = new FibonacciSequence();
    // 2.调用方式计算并打印计算结果
    int res1 = fs.fib1(10);
    System.out.println("递归计算结果是:" + res1);
    int res2 = fs.fib2(10);
    System.out.println("递推计算结果是:" + res2);
  }
}

此时需要先编译、再执行,不能直接java filename 来运行。

先编译javac FibonacciSequenceTest.java,会同时生成FibonacciSequence.javaFibonacciSequenceTest.java的字节码文件,再执行java FibonacciSequenceTest

(2)封装的概念

封装是面向对象的一大特性。

通常情况下可以在测试类中给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示,但是会与现实生活中的情况不符。

新建Student功能类:

/*
  Student类的封装
*/

public class Student {
  
  int id; // 学号
  String name; // 姓名
  
  void print() {
    System.out.println("我是" + name + ",我的学号是" + id);
  }
}

再建测试类:

/*
  Student类的测试类
*/

public class StudentTest {
  
  public static void main(String[] args) {
    
    // 1.声明Student类型的引用指向Student类型的对象
    Student stu1 = new Student();
    Student stu2 = new Student();
    // 2.对成员变量赋值并打印
    stu1.id = 12321;
    stu1.name = "Corley";
    stu1.print();
    
    stu2.id = -12321;
    stu2.name = "Jack";
    stu2.print();
  }
}

输出:

我是Corley,我的学号是12321
我是Jack,我的学号是-12321

可以看到,在给stu2进行赋值时,id为负值,这符合Java中整型的标准,即是合法的,但是与现实生活中的情况并不相符,因为没有学号是负值。

为了避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐藏成员变量的细节 以及保证成员变量数值的合理性 ,该机制就叫做封装

(3)封装的实现

封装的实现步骤如下:

  1. 私有化成员变量,使用private 关键字修饰。

????private关键字修饰表示私有的含义,也就是该成员变量只能在当前类的内部使用

????之前访问成员变量的方式失效,例如stu2.id`` = -12321; 就不能再正常编译通过。

  1. 提供公有的get和set方法,并在方法体中进行合理值的判断。

????使用public关键字修饰,该方法可以在任意位置使用

????没有修饰符的方法和变量是默认的访问权限,级别介于private和public之间。

  1. 在构造方法中调用set方法进行合理值的判断。

Student类如下:

/*
  Student类的封装
*/

public class Student {
  
  // 1.私有化成员变量,使用private关键字修饰
  private int id; // 学号
  private String name; // 姓名
  
  public Student() {}
  
  // 3.在公有的构造方法中调用set方法进行合理值的判断
  public Student(int id, String name) {
    setId(id);
    setName(name);
  }
  
  // 2.提供公有的get和set方法,并在方法体中进行合理值的判断
  public int getId() {
    return id;
  }
  
  public void setId(int id) {
    if (id > 0) {
      this.id = id;
    } else {
      System.out.println("学号不合理!!!");
    }
  }
  
  public String getName() {
    return name;
  }
  
  public void setName(String name) {
    this.name = name;
  }
  
  public void print() {
    System.out.println("我是" + getName() + ",我的学号是" + getId());
  }
}

StudentTest类如下:

/*
  Student类的测试类
*/

public class StudentTest {
  
  public static void main(String[] args) {
    
    // 1.声明Student类型的引用指向Student类型的对象
    Student stu1 = new Student();
    Student stu2 = new Student();
    // 2.对成员变量赋值并打印
    /*
    stu1.id = 12321;
    stu1.name = "Corley";
    stu1.print();
    
    stu2.id = -12321;
    stu2.name = "Jack";
    stu2.print();
    */
    stu1.setId(12321);
    stu1.setName("Corley");
    stu1.print();
    
    System.out.println("-------------------------------------------");
    stu2.setId(-12321);
    stu2.setName("Jack");
    stu2.print();
    
    System.out.println("-------------------------------------------");
    Student stu3 = new Student(-45654, "Bob");
    stu3.print();
  }
}

输出:

我是Corley,我的学号是12321
-------------------------------------------
学号不合理!!!
我是Jack,我的学号是0
-------------------------------------------
学号不合理!!!
我是Bob,我的学号是0

此时Student类就是封装类。

(4)封装类实现学生信息的录入

提示用户输入班级的学生人数以及每个学生的信息,学生的信息有:学号、姓名,最后分别打印出来。
提示:Student[] arr = new Student[num];

Student类使用前面定义的Student类,StudentTest类如下:

/*
  Student信息的录入和打印
*/

import java.util.Scanner;

public class StudentTest {
  
  public static void main(String[] args) {
    
    // 1.提示用户输入学生人数
    System.out.println("请输入学生人数:");
    Scanner sc = new Scanner(System.in);
    int count = sc.nextInt();
    
    // 2.根据人数声明对应的一维数组
    Student[] stus = new Student[count];
    
    // 3.提示用户输入每个学生的信息并保存到一维数组
    for (int i = 0; i < count; i++) {
      System.out.println("请输入第" + (i + 1) + "个学生的信息(学号 姓名):");
      stus[i] = new Student(sc.nextInt(), sc.next());
    }
    
    // 4.打印所有学生的信息
    System.out.println("所有学生的信息为:");
    for(int i = 0; i < count; i++) {
      stus[i].print();
    }
  }
}

输出:

请输入学生人数:
3
请输入第1个学生的信息(学号 姓名):
12321 Corley
请输入第2个学生的信息(学号 姓名):
12322 Jack
请输入第3个学生的信息(学号 姓名):
12323 Bob
所有学生的信息为:
我是Corley,我的学号是12321
我是Jack,我的学号是12322
我是Bob,我的学号是12323

其中,Student[] stus = new Student[count]; 的含义是:

数组中的每个元素都是Student类型,即数组中的每个元素都可以看做Student类型的变量,所以对每个元素进行初始化时可以采用arr[i] = new Student(); 的方式。

(5)JavaBean的概念

JavaBean是一种Java语言写成的可重用组件,其他Java 类可以通过反射机制发现和操作这些JavaBean 的属性。
JavaBean本质上就是符合以下标准的Java类:

  • 类是公共的

  • 有一个无参的公共的构造器

  • 有属性,且有对应的get、set方法

可以看到,JavaBean其实就是一个封装类

总结

方法是一个类实现一定功能的基础,同时方法具有重载、递归等特性;作为面向对象的三大特征之一,封装将对象内部的成员封闭起来,不对外开放,同时增加了对用户合理性的判断,防止了用户的恶意操作,从而保证了对象的完整性。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 16:31:00  更:2021-08-23 16:31:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/31 2:04:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码