当前位置: 首页 > news >正文

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

1.3 课前问题列表

方法相关问题

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的功能各是什么?
changeStr(String x) 的功能:接收一个字符串参数 x,并尝试将其重新赋值为 "xyz"。
changeArr(String[] strs) 的功能:该方法接收一个字符串数组,并遍历数组,将每个元素修改为原元素值加上其索引。

1.2 main方法的x有没有被改变?为什么?
没有被改变。
原因:
Java的参数传递是值传递(pass by value)。当调用 changeStr(x) 时,传递的是变量 x 的引用的副本(而不是引用本身)。
字符串是不可变对象,x = "xyz" 只是将方法内的局部参数 x(引用的副本)指向了新的字符串 "xyz",但原始变量 x 仍然指向原来的字符串 "abc"。

1.3 main方法的args数组的内容有没有被改变?为什么?
main方法的args数组的内容被改变。
原因:
Java的参数传递是值传递,但对于引用类型,传递的是引用的副本,即副本和原始引用指向同一个数组对象。
changeArr 方法通过这个引用副本遍历数组,并修改了每个元素的值。由于修改的是同一数组对象的内容,因此原始数组(即 args)的内容被改变。

1.4 args数组中的值是从哪里来的?要怎么才能给他赋值。
1)args 数组中的值来自命令行参数(command-line arguments),即在运行程序时通过命令行传入的参数。
2) 有以下几种方式可以给 args 赋值:
a)命令行直接传入(最常用):
例如,编译并运行程序:

      bash

       javac Main.java

       java Main arg1 arg2 arg3

则 args 数组为 ["arg1", "arg2", "arg3"]。
b)通过IDE配置:
在IDE(如IntelliJ IDEA、Eclipse)中运行程序时,可以在运行配置中设置命令行参数。

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 这段程序输出结果是什么?为什么?

  String[] strArr = {"aa","bb","cc"};

  strArr[1] = "xx";

  System.out.println(Arrays.toString(strArr));

输出结果:[aa, xx, cc]
原因:
1)字符串数组 strArr 初始化为 {"aa","bb","cc"}。
2)通过 strArr[1] = "xx"; 将索引1的元素(原为"bb")重新赋值为"xx"。
(数组是可变的数据结构,允许通过索引修改元素的值。)
3)修改后数组变为 ["aa", "xx", "cc"],Arrays.toString(strArr) 输出该内容。

2.2 字符串是不可变类,为什么可以对strArr[1]赋值"xx"。
字符串不可变指的是字符串对象本身的内容不可改变。即无法修改像"bb"这个字符串对象的内容,无法将它的某个字符改成其他字符。
但数组是可变的,即可以修改数组元素指向的对象。

3.使用int[5][]定义一个二维数组,其第二维到底有多长?尝试补全代码,然后使用foreach获其他循环方法遍历这个二维数组?
使用 int[5][] 定义的是一个第二维长度不确定的数组。第一维长度固定为5即5行,但第二维每个元素(每行)目前都是 null,需要手动初始化每行的长度。

补全代码:

    public class Main {

        public static void main(String[] args) {

  

    int[][] arr = new int[5][];

   

    arr[0] = new int[3];  // 第0行长度为3

    arr[1] = new int[2];  // 第1行长度为2

    arr[2] = new int[4];  // 第2行长度为4

    arr[3] = new int[1];  // 第3行长度为1

    arr[4] = new int[5];  // 第4行长度为5

    for (int i = 0; i < arr.length; i++) {

        for (int j = 0; j < arr[i].length; j++) {

            arr[i][j] = i * 10 + j;  // 任意赋值

        }

    }

    System.out.println("使用嵌套for循环:");

    for (int i = 0; i < arr.length; i++) {

        for (int j = 0; j < arr[i].length; j++) {

            System.out.print(arr[i][j] + " ");

        }

        System.out.println();

    }

    System.out.println("\n使用foreach循环:");

    for (int[] row : arr) {

        for (int num : row) {

            System.out.print(num + " ");

        }

        System.out.println();

    }

4.类与对象的区别是什么? Math类有对象吗?String类有什么属性是private的,有什么方法是public的,为什么这样设计(尝试举两例说明)?
1)类(Class):是一个模板或蓝图,定义了对象的结构和行为。
对象(Object):是类的一个具体实例,占用内存空间并存储实际数据。
2)Math类没有对象。Math 类被设计为工具类,所有方法都是static的,并且构造器是private的,因此无法创建Math对象。
3)String类的private属性:

    private final byte[] value

      private final int hash (缓存哈希值)

    private final byte coder (编码标识)

String类的public方法(部分):

public int length()

public char charAt

public String substring

4)例1:private final byte[] value(存储数据的数组被私有化)
为什么私有?
防止外部直接修改数组内容(字符串不可变的核心保障)。
如果数组是public,用户可能通过str.value[0] = 'x'修改字符串内容,破坏不可变性。
为什么提供public方法(如charAt())?
通过公共方法安全地访问数据(方法内部可做边界检查,避免数组越界)。
例如:charAt(int index) 方法会检查index是否合法,再返回对应字符。
例2:private final int hash(缓存哈希值)
为什么私有?
哈希值计算需要成本,缓存后可提高性能(如用于HashMap键值),但缓存过程对用户应该是透明的。
如果hash是public,用户可能错误地修改它,导致哈希不一致。
为什么提供public的hashCode()方法?
允许用户获取哈希值,但内部实现延迟计算(第一次调用时计算并缓存,后续直接返回缓存值)。
这样既保证了效率,又封装了实现细节。

5.将类的属性设置为public可以方便其他类访问,但为什么Java中普遍使用setter/getter模式对对象的属性进行访问呢?这与封装性又有什么关系?
1)封装性是面向对象的核心原则
封装性要求将对象的内部状态(属性)隐藏起来,只通过受控的接口进行访问。setter/getter模式正是实现封装的关键手段。
2)setter/getter模式 vs public属性的优势
a)控制访问权限(安全性)
public属性:任何类都可以直接修改属性,可能破坏对象状态的完整性。例如,设置非法值。
setter方法:可以在方法中添加验证逻辑,确保赋值合法。

    public void setAge(int age) {

        if (age < 0 || age > 150) {

        throw new IllegalArgumentException("年龄不合法");

      }

    this.age = age;

      }

b)实现只读或只写属性
如果属性是public,无法限制只读或只写。
通过只提供getter(无setter)实现只读属性:

    private String id;  // 只读属性

    public String getId() { return id; }  // 无setter

c)隐藏内部实现细节(灵活性)
内部存储方式改变时,不影响外部代码(例如,属性名或类型变化)。

  // 存储秒数

        private long timeInSeconds;

        public long getTime() { return timeInSeconds; }

d)支持延迟初始化
通过getter延迟加载资源,提高性能:

      private HeavyObject heavy;

      public HeavyObject getHeavy() {

      if (heavy == null) {

          heavy = new HeavyObject(); 

    }

      return heavy;

    }

6.对象的属性可在什么时候进行初始化?都有哪些进行初始化的办法?
1)声明时即编译时,直接初始化
2)构造器初始化或初始化块,即创建对象时
3)延迟初始化,即第一次使用时
初始化方法:
a)声明时直接初始化

        public class Person {

          private String name = "未知";          // 直接初始化

          private static int count = 0;         // 静态属性初始化

          private final int id = generateId();  // 方法调用初始化

          }   

  b)构造器初始化

        public class Person {

        private String name;

        private int age;

        public Person(String name, int age) {

            this.name = name;

            this.age = age;

        }

          }

  c)初始化块

        public class Person {

        private String name;

        private List<String> hobbies;

     

    // 实例初始化块(每次创建对象时执行)

    {

        name = "临时姓名";

        hobbies = new ArrayList<>();

        hobbies.add("阅读");

    }

    // 静态初始化块

      private static Map<String, Integer> config;

    static {

        config = new HashMap<>();

        config.put("max_age", 150);

        config.put("min_age", 0);

    }

}

d)延迟初始化

      public class Database {

      private Connection connection;

      public Connection getConnection() {

        if (connection == null) {

          connection = createConnection();

      }

          return connection;

      }

      private Connection createConnection() {

          // 创建数据库连接

          return new Connection();

      }

    }

http://www.dtcms.com/a/395771.html

相关文章:

  • 词性标注技术漫谈:为词语赋予语法灵魂的旅程
  • K230基础-MicroPython
  • 网站访问问题:无法访问此网站、404
  • Redis 与Memcached 的对比
  • PyTorch 神经网络工具箱:核心原理与实践指南
  • 广义矩估计错误指定时的一个推导【续5】
  • 【STM32】ADC数模转换器
  • Tensorboard学习记录
  • Redis中常见数据结构底层实现结构是什么
  • 高频交易技术演进:从毫秒到纳秒的极限延迟优化之路
  • 从零开始搭建并部署一个基于Django和YOLO的智能模型项目
  • MySQL零基础学习Day2——数据库基础操作
  • 数学笔试选择题:题组1
  • Linux常用命令51——tail查看文件尾部内容
  • Django多数据库配置:mysql、mongo、redis、达梦
  • 图像拼接(反向拼接巨难,求指教!)
  • [免费]基于Python的深度学习音乐推荐系统(后端Django)【论文+源码+SQL脚本】
  • 南华 NHL-1 型加载减速工况法轻型柴油车烟度检测系统:技术解析与实战指南
  • 学习Java遇到的一些问题
  • 基于SpringBoot招聘信息管理系统
  • 多线程—线程通信之notifyAll()/wait()方法Demo
  • kotlin 常用函数
  • 2025年CSP-J1入门级初赛题解
  • vue3的基本指令以及对js的导入和导出
  • Linux 基础:关机与重启
  • React Native:分享Windows平台搭建react native并构建apk的操作流程和配置信息
  • EC24026露营灯警示灯芯片方案 报警声语音IC 单片机方案开发
  • 反量化的详细过程
  • C语言:实现3x3矩阵对角线求和
  • [Maven 基础课程]Maven 工程继承和聚合