首页 > 编程语言 >2024-第02周 预习、实验与作业:Java基础语法2、面向对象入门

2024-第02周 预习、实验与作业:Java基础语法2、面向对象入门

时间:2024-09-10 10:52:33浏览次数:14  
标签:02 初始化 Java int 2024 对象 数组 字符串 属性

课前问题列表

1.方法相关问题

public class Main {
    static void changeStr(String x) {
        x = "xyz";
    }
    static void changeArr(String[] strs) {
        for (int i = 0; i < strs.length; i++) {
            strs[i] = strs[i]+""+i;
        }
    }
 
    public static void main(String[] args) {    
        String x = "abc";
        changeStr(x);
        System.out.println(x);
        changeArr(args);
        System.out.println(Arrays.toString(args));
    }
}

对于如上代码:

1.1 changeStr与changeArr的功能各是什么?

1.2 main方法的x有没有被改变?为什么?

1.3 main方法的args数组的内容有没有被改变?为什么?

1.4 args数组中的值是从哪里来的?要怎么才能给他赋值

1.1

  • changeStr 方法的功能是尝试改变传入的字符串 x 的值为 "xyz"。然而,由于 Java 中字符串是不可变的(immutable),这个操作实际上不会改变原字符串 x 的值,而是让局部变量 x 指向了一个新的字符串对象 "xyz"。但这个改变不会影响  main 中的 x 的值。
  • changeArr 方法的功能是遍历传入的字符串数组 strs,并将每个字符串元素与它的索引(转换为字符串)拼接起来。这个操作会修改数组中的每个元素,因此会影响传入的数组本身。

 1.2

  • main方法的x没有被改变。 changeStr(x) 方法试图将 x 的值更改为 "xyz",但由于 Java 字符串的不可变性,这个改变仅作用于方法内部的局部变量 x,而不影响 main 方法中原始变量 x 的值。

1.3

  • main 方法中的 args 数组的内容被改变了。因为 args 是一个对象(字符串数组),当它被传递给 changeArr(args) 方法时,传递的是数组对象的引用。在 changeArr 方法内部,通过数组引用对数组元素进行的修改会反映到原始数组上。 

1.4 

  • args数组中的值 是从命令行参数中来的。当你从命令行运行 Java 程序时,可以指定一系列的参数,这些参数会被 Java 运行时系统作为字符串数组传递给程序的 main 方法的 args 参数。

  • 给args赋值:不能直接在 Java 代码中给 args 赋值,因为它是 main 方法的参数,由 Java 运行时系统在程序启动时提供。但是可以在 main 方法内部创建和修改新的字符串数组,并使用这些数组来模拟或处理 args 数组的内容。

  • 例如,需要在程序中模拟命令行参数,可以这样:

    public static void main(String[] args) {  
        // 假设我们想模拟命令行参数  
        String[] simulatedArgs = {"arg1", "arg2", "arg3"};  
          
        // 可以使用 simulatedArgs 代替 args 进行操作  
        changeArr(simulatedArgs);  
        System.out.println(Arrays.toString(simulatedArgs));  
    }

    这样可以在不需要实际从命令行接收参数的情况下,测试和处理类似 args 的数组。

2. 数组相关问题

对于如下程序:

int[] arr = new int[3];
arr[0] = 1; arr[1] = 1;
int[] arrX = arr;
arr[0] = 2;
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(arrX));

 2.1 这段程序输出结果是什么?为什么?

输出结果:

[2, 1, 0]  
[2, 1, 0]

为什么:

  • int[] arr = new int[3]; 创建了一个长度为3的整型数组,初始时所有元素被自动初始化为0。
  • arr[0] = 1; arr[1] = 1; 将数组的第一个和第二个元素分别设置为1。
  • int[] arrX = arr; 这行代码并没有创建数组的副本,而是让arrXarr指向同一个数组对象。因此,arrXarr是同一个数组的两个引用。
  • arr[0] = 2; 修改了数组的第一个元素为2。由于arrXarr指向同一个数组,这个修改也会反映在arrX上。
  • System.out.println(Arrays.toString(arr)); 和 System.out.println(Arrays.toString(arrX)); 输出的是同一个数组的内容,所以两者输出的结果一样。数组的第三个元素没有被显式设置,所以它保持其初始值0。
String[] strArr = {"aa","bb","cc"};
strArr[1] = "xx";
System.out.println(Arrays.toString(strArr));

 2.2 字符串是不可变类,为什么可以对strArr[1]赋值"xx"?

输出结果:

[aa, xx, cc]

为什么:

  • 字符串在Java中是不可变的(immutable),这意味着一旦字符串对象被创建,其内容(字符序列)就不能被改变。然而这并不影响数组本身的可变性。在上面的例子中,strArr 是一个字符串数组,不是字符串对象本身。
  • 当执行 strArr[1] = "xx"; 时,并没有改变 strArr[1] 原来的字符串对象(即 "bb"),而是让 strArr[1] 引用了一个新的字符串对象 "xx"。数组 strArr 仍然是一个可变对象,它可以持有对任何字符串对象的引用,包括在程序执行过程中新创建的字符串对象。
  • 字符串是不可变的,但字符串数组(或任何对象数组)是可变的,我们可以更改数组中元素的引用,即使这些元素本身是不可变的对象。

 

3.使用int[5][]定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach获其他循环方法遍历这个二维数组?

  • 在Java中,当使用int[5][]定义一个二维数组时,实际上是在创建一个一维数组,其元素类型是int[](即整型数组)。这个一维数组的长度是5,意味着它可以存储5个整型数组(第二维)。但是,这些第二维数组(即每个int[])的长度在初始时是不确定的,并且每个第二维数组的长度可以独立设置。

补全代码:

public class Main {  
    public static void main(String[] args) {  
        int[][] twoDArray = new int[5][];  
 
        twoDArray[0] = new int[2]; // 第一行长度为2  
        twoDArray[1] = new int[3]; // 第二行长度为3  
        twoDArray[2] = new int[1]; // 第三行长度为1  
        twoDArray[3] = new int[4]; // 第四行长度为4  
        twoDArray[4] = new int[5]; // 第五行长度为5  
   
        for (int i = 0; i < twoDArray.length; i++) { // 遍历第一维  
            for (int j = 0; j < twoDArray[i].length; j++) { // 遍历第二维  
                twoDArray[i][j] = i * j; // 给每个元素赋值  
                System.out.print(twoDArray[i][j] + " "); 
            }  
            System.out.println();
        }  
  
        // 使用foreach循环遍历二维数组  
        for (int[] row : twoDArray) { // 遍历第一维  
            for (int val : row) { // 遍历当前行的每个元素  
                System.out.print(val + " ");  
            }  
            System.out.println();  
        }  
    }  
}
  • 在这个例子中,我首先创建了一个int[5][]类型的二维数组twoDArray,然后分别为它的每个第二维数组分配了不同的长度,并使用嵌套的for循环来遍历和初始化这个二维数组。之后,我展示了两种遍历这个二维数组的方法:一种是使用嵌套的for循环,另一种是使用嵌套的foreach循环(注意foreach不能直接用于二维数组的第二维,所以需要先用foreach遍历第一维,然后在内部使用另一个foreach遍历当前行的每个元素)。

 

4.类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?

类与对象的区别:

  • 类(Class) 是对一组具有相同属性和行为的对象的抽象描述。它定义了一个对象的模板或蓝图,指定了对象可以拥有的属性和行为(即方法和属性)。类是一种引用数据类型,用于创建对象。
  • 对象(Object) 是根据类创建的实例。每个对象都有自己独立的属性(成员变量)和行为的特定值(成员方法)。对象可以看作是类的具体表现。

Math类有对象吗? 

  • Math类没有对象。Math类是一个包含用于执行基本数学运算的方法的类,如指数、对数、平方根、三角函数等。Math类中的方法都是静态的(static),这意味着可以直接通过类名调用它们,而无需创建Math类的对象。例如,Math.abs(-10)用于计算-10的绝对值,这里并没有创建Math类的实例。

String类的私有属性和公有方法 :

  • String类的私有属性(通常包括用于存储字符序列的内部数据结构)对外部是不可见的。这些私有属性确保了String对象的封装性,即隐藏了对象的内部表示,仅通过公共接口与外界交互。
  • String类的公有方法(例如length()charAt(int index)substring(int beginIndex, int endIndex)equals(Object anObject)toLowerCase()toUpperCase()等)允许我们访问和操作String对象。这些公有方法的设计目的是为了提供字符串处理的功能,同时保护String对象的内部状态不被随意修改(因为String对象是不可变的)。

为什么这样设计? 

私有属性的设计原因

  1. 封装:隐藏对象的内部状态,仅通过公共接口与外界交互,增强了数据的安全性和类的模块化。
  2. 灵活性:私有属性允许类内部实现细节的改变,而不需要修改使用类的代码。

公有方法的设计原因

  1. 易用性:提供明确、一致的接口,使得其他类可以方便地调用String对象的功能。
  2. 安全性:通过控制对对象状态的访问,可以防止不恰当的修改,特别是在String对象为不可变类型时。

例子

  1. length()方法:这是一个公有方法,用于获取字符串的长度。它是public的,因为这是一个常用的操作,而且字符串的长度是外部需要知道的信息。
  2. charAt(int index)方法:这也是一个公有方法,用于获取字符串指定位置的字符。它同样是public的,因为访问字符串中的特定字符是常见的需求。

这些公有方法的设计使得String类非常灵活和强大,同时保持了其内部状态的安全性和一致性。

 

5.将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?

  • 在Java中,尽管将类的属性设置为public可以方便其他类直接访问,但这种做法并不被推荐,主要原因与封装性(Encapsulation)紧密相关。封装性是面向对象编程(OOP)的一个核心概念,它要求将对象的状态信息(即属性)隐藏在对象内部,不允许外部直接访问,而是通过公共的接口(即方法)来对对象的状态进行查询和修改。
  • 使用setter/getter模式(也称为访问器(Accessor)和修改器(Mutator)方法)对对象的属性进行访问,正是为了实现封装性的一个重要手段。

主要原因:

  1. 隐藏内部实现:通过将属性设置为private,类的内部实现被隐藏起来,这样即使类的内部结构发生变化(例如,更换存储属性的数据结构),只要保持setter/getter方法的签名不变,就不会影响到使用这个类的其他代码。这提高了类的可维护性和可扩展性。

  2. 控制访问:setter/getter方法允许在属性被访问或修改时加入额外的逻辑。例如,可以在setter方法中加入验证逻辑,以确保属性值的有效性;在getter方法中,可以基于某些条件返回不同的结果或计算值。这种控制访问的能力是public属性所无法提供的。

  3. 灵活性:随着软件的发展,对类属性的访问需求可能会发生变化。如果属性是public的,那么改变访问方式可能会影响到很多使用这个属性的代码。而如果使用setter/getter方法,则可以通过修改方法实现来改变访问逻辑,而无需修改使用这个类的其他代码。

  4. 数据安全性:通过setter/getter方法可以保护对象的状态不被非法修改。例如,可以确保某些属性在对象创建后就不能被修改(只需不提供setter方法即可),或者确保属性值始终满足特定的约束条件(在setter方法中加入验证逻辑)。

综上所述,使用setter/getter模式对对象的属性进行访问,是Java中实现封装性的一个重要手段。它不仅提高了类的可维护性、可扩展性和灵活性,还增强了数据的安全性。因此,在Java中普遍推荐使用setter/getter模式来访问对象的属性。

 

6.对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?

声明时初始化

  • 在类的成员变量声明时直接初始化。这种方式在对象创建之前就已经确定了属性的初始值,但这是在类加载到JVM时发生的,而不是在对象创建时。
public class MyClass {  
    private int myNumber = 42; // 声明时初始化  
}

构造方法中初始化

  • 在构造方法(Constructor)中初始化对象的属性。这是最常见的初始化方式之一,因为它允许在创建对象时根据需要设置不同的初始值。
public class MyClass {  
    private int myNumber;  
  
    public MyClass() {  
        myNumber = 0; // 无参构造方法初始化  
    }  
  
    public MyClass(int number) {  
        myNumber = number; // 带参构造方法初始化  
    }  
}

初始化块中初始化

  • Java允许在类中定义初始化块(Initialization Blocks),这些块在构造方法执行之前执行,并且每次创建对象时都会执行。初始化块可以是静态的(static)或非静态的。静态初始化块用于初始化静态变量,而非静态初始化块用于初始化实例变量。
public class MyClass {  
    private int myNumber;  
  
    {  
        // 非静态初始化块  
        myNumber = 10;  
    }  
  
    static {  
        // 静态初始化块,用于静态变量  
        // 这里通常不用于实例变量的初始化  
    }  
}

 

通过setter方法初始化

  • 在对象创建之后,通过调用对象的setter方法来设置属性的值。这种方式提供了更大的灵活性,允许在对象创建后的任何时间修改属性值。
public class MyClass {  
    private int myNumber;  
  
    // setter方法  
    public void setMyNumber(int number) {  
        myNumber = number;  
    }  
}  
  
// 使用  
MyClass obj = new MyClass();  
obj.setMyNumber(20); // 通过setter方法初始化

 

标签:02,初始化,Java,int,2024,对象,数组,字符串,属性
From: https://blog.csdn.net/2301_79959806/article/details/142089983

相关文章

  • Java并发编程实战 11 | 线程活跃问题(死锁,活锁和饥饿)
    并发应用程序的“活跃度”指的是它及时执行并完成任务的能力。活跃性问题则是指程序无法最终得到预期的运行结果。相比于线程安全问题,存活性问题可能会导致更严重的后果。例如,死锁会使程序完全停滞,导致无法继续执行。常见的活跃性问题包括以下三种:1.死锁(Deadlock)死锁发......
  • 02 面向对象的系统分析与面向对象需求分析是一个概念吗?
    面向对象的系统分析与面向对象需求分析在软件开发过程中是两个相关但有所区别的概念。以下是对这两个概念的详细解析:面向对象的系统分析面向对象的系统分析是在系统开发的前期阶段,运用面向对象的思想和方法对系统进行全面分析的过程。它不仅关注系统的功能需求,还关注系统的非功......
  • 2024ccpc线性基与校赛线性基
    异或空间线性基我终于意识到写题解有多重要了2024CCPC网络赛ProblemJ.找最小Mandy发现了两个很好玩的长度为\(n\)的序列,记为\(a,b\),她觉得一个序列的无趣度为序列内所有元素的异或和。现在她想要这两个序列尽可能有趣,具体来说,她希望最无趣的序列尽可能有趣。她觉得交......
  • 本周新上技术岗:Java/C/C++/GO语言/测试开发,月薪最高40K!
    本周新上技术岗位推荐,Java/C++/GO语言/前后端开发等高薪岗位招人啦,外企招人不加班,月薪最高40K,还不快来!!抓紧投递,早投早入职!......
  • 2024-09-04:用go语言,给定一个长度为n的数组 happiness,表示每个孩子的幸福值,以及一个正
    2024-09-04:用go语言,给定一个长度为n的数组happiness,表示每个孩子的幸福值,以及一个正整数k,我们需要从这n个孩子中选出k个孩子。在筛选过程中,每轮选择一个孩子时,所有尚未选中的孩子的幸福值都会减少1。需要注意的是,幸福值不能降低到负数,只有在其为正数时才能减少。我们的目标是尽可......
  • CCPC Online 2024China, September, 8, 2024三道签到题
    网络赛复现地址:https://codeforces.com/gym/105336 L网络预选赛:做法:直接枚举两行两列即可代码:#include<bits/stdc++.h>usingnamespacestd;constintN=510;chara[N][N];intmain(){intn,m;cin>>n>>m;for(inti=0;i<n;i++)for......
  • 稀疏数组__Java演示
    数据结构是一种数据组织、管理和存储的格式。常见的有数组、栈、队列、链表、树、图、堆、哈希表……当需要记录一盘五子棋对弈的数据时,通常可以采用二维数组来实现,显然直接使用二维数组来存储数据有浪费memory的嫌疑,因为棋盘上很多点位没有落子,这些冗余数据也被记录了。 9x9......
  • 2-7Java接口
    Java接口接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法......
  • Java面试题-基础和框架-Java面试题二
    1、什么是抽象类?在Java中,抽象类用于创建具有某些被子类实现的默认方法的类,一个抽象类可以有没有方法体的抽象方法,也可以有和普通类一样有方法体的方法。abstract关键字用于声明一个抽象类,抽象类无法实例化,主要用于为子类提供一个模板,子类需要覆盖抽象方法。2、抽象类......
  • javascript-day02
    02-BOM-01-window的对话框<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Docu......