《JAVA编程思想》学习备忘(第155页:Initialization & Cleanup)-6

本文讲解Java中的实例初始化块及数组初始化方法,包括基本类型的数组初始化和对象数组的初始化过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 续《JAVA编程思想》学习备忘(第155页:Initialization & Cleanup)-5
Non-static instance initialization
Java 提供一种相似的语法,叫做实例初始化,用来为每个对象初始化非静态变量。
举例:
//:initialization/Mugs.java
// Java "Instance Initialization."
import static staticPrint.Print.print;
class Mug{
    Mug(int marker){
        print("Mug("+marker+")");
    }
    void f(int marker){
        print("f("+marker+")");
    }
}
public class Mugs{
    Mug mug1;
    Mug mug2;
    {
        mug1 = new Mug(1);
        mug2 = new Mug(2);
        print("mug1 & mug2 initialized");
    }
    Mugs(){
        print("Mugs()");
    }
    Mugs(int i){
        print("Mugs(int)");
    }
    public static void main(String[] args){
        print("Inside main()");
        new Mugs();
        print("new Mugs() completed");
        new Mugs(1);
        print("new Mugs(1) completed");
    }
}
输出结果: 
Inside main()
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs()
new Mugs completed
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs(int)
new Mugs(1) completed
你可以看到实例初始化从句:
  {
      mug1 = new Mug(1);
      mug2 = new Mug(2);
      print("mug1 & mug2 initialized");
  }
实例初始化从句在构造方法之前执行。
 
Array initialization
An array is simply a sequence of either objects or primitives that are all the same type and are packaged together under one identifier name.Arrays are defined and used with the square-brackets indexing operator[].To define an array reference,you simply follow your type name with empty square brackets:
int[] a1;
You can also put the square brackets after the identifier to produce exactly the same meaning:
int a1[]
……要创建数组存储空间,你必须写一个初始化的表达式。对数组来说,可在你的代码任意处初始化,但你也可用一种特别的初始化表达式,它必须发生在数组创建之处。举例:
int[] a1 = {1,2,3,4,5};
也可这样付值:
int[] a2;
a2=a1;
 
举例:
//:initialization/ArrayOfPrimitives.java
import static staticPrint.Print.print;
public class ArrayOfPrimitives{
    public static void main(String[] args){
        int[] a1 = {1,2,3,4,5};
        int[] a2;
        a2 = a1;
        for(int i = 0; i < a2.length; i++)
            a2[i]=a2[i]+1;
        for(int i = 0; i < a1.length; i++)
            print("a1["+i+"]="+a1[i]);
    }
}
输出结果:
a1[0]=2
a1[1]=3
a1[2]=4
a1[3]=5
a1[4]=6
你可以看到a2改变,a1显现。此为引用付值。
 
所有的数组有一个内在的成员,你可查询,但不可改变,告诉你数组中有多少元素,这个成员是length 。
当写程序时如果你不知道在你的数组中需要多少元素怎么办?你只需使用new来创建数组元素。这里,尽管new工作创建了一个原始数据数组(new不会创建一个非数组原始数据类型):
//:initialization/ArrayNew.java
//Creating arrays with new.
import java.util.*;
import static staticPrint.Print.print;
public class ArrayNew{
    public static void main(String[] args){
        int[] a;
        Random rand = new Random(47);
        a = new int[rand.nextInt(20)];
        print("length of a = " + a.length);
        print(Arrays.toString(a));
    }
}
输出结果:
length of a = 18
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
程序输出结果显示原始数据类型数组元素被自动地初始化为“空”值。(对numerics和char,这是0,而对boolean,它是false)
当然,上例数组也可被定义和初始化在同样的陈述句:
int[] a = new int[rand.nextInt(20)];
 
如果你创建一个非原始数据数组,你创建一个对象数组,考虑包装类型Integer,它是一个类而不是一个原始数据类型:
//:initialization/ArrayClassObj.java
//Creating an array of nonprimitive objects.
import java.util.*;
import static staticPrint.Print.print;
public class ArrayClassObj{
    public static void main(String[] args){
        Random rand = new Random(47);
        Integer[] a = new Integer[rand.nextInt(20)];
        print("length of a = " + a.length);
        for(int i = 0; i < a.length; i++)
            a[i] = rand.nextInt(500);//Autoboxing
        print(Arrays.toString(a));      
    }
}
输出结果:(样板)
length of a = 18
[55,193,361,461,429,368,200,22,207,288,128,51,89,309,278,498,361,20]
这里,即使new之后创建数组:
Integer[] a = new Integer[rand.nextInt(20)];
它仅为一个对象数组,而初始化没有完成直到对象自身被初始化通过创建一个新的Integer对象(此例中通过autoboxing):
a[i] = rand.nextInt(500);
如果你忘记创建对象,无论如何,当你尝试使用这个空数组位置你将得到一个运行异常。
 
它也可能初始化对象数组通过使用大括号包裹的列表,这里有两种形式:
//:initialization/ArrayInit.java
//Array initialization.
import java.util.*;
public class ArrayInit{
    public static void main(String[] args){
        Integer[] a = {
            new Integer(1),
            new Integer(2),
            3,//Autoboxing
        };
        Integer[] b = new Integer[]{
            new Integer(1),
            new Integer(2),
            3,//Autoboxing
        };
        System.out.println(Arrays.toString(a));
        System.out.println(Arrays.toString(b));
    }
}
输出结果:
[1,2,3]
[1,2,3]
 
尽管第一种形式很有用,它有更多的限制,因为它仅能被在数组定义之处使用。你可以到处使用第二种和第三种形式,即使在一个被调用方法内。举一个例子:
//:initialization/DynamicArray.java
//Array initialization.
public class DynamicArray{
    public static void main(String[] args){
        Other.main(new String[]{"fiddle","de","dum"});
    }
}
class Other{
    public static void main(String[] args){
        for(String s : args)
            System.out.println(s + " ");
    }
}
输出结果:
fidde de dum
 
(待续)
 
你遇到的错误信息如下: ``` error: invalid initialization of non-const reference of type &#39;std::__cxx11::string&amp;&#39; from an rvalue of type &#39;std::__cxx11::string&#39; ``` 这是 C++ 编译器在尝试将一个 **临时对象(rvalue)** 绑定到一个 **非常量左值引用(non-const lvalue reference)** 时发生的编译错误。 --- ## 🔍 错误原因分析 ### 示例代码(导致错误): ```cpp void func(string&amp; s) { cout &lt;&lt; s &lt;&lt; endl; } int main() { func(&quot;hello&quot;); // ❌ 编译错误:临时对象不能绑定到非 const 引用 } ``` ### 解释: - `&quot;hello&quot;` 是一个字符串字面量(`const char*`),它会被隐式转换为一个 `std::string` 的**临时对象(rvalue)**。 - 函数 `func(string&amp; s)` 接受的是一个**非常量左值引用**。 - 在 C++ 中,**不能将临时对象绑定到非常量左值引用上**,因为临时对象是只读的,而函数可能修改这个引用的内容,这是不允许的。 --- ## ✅ 正确解决方法 ### 方法一:将函数参数改为常量引用(推荐) 如果你不需要修改传入的字符串内容,应使用 `const string&amp;`: ```cpp void func(const string&amp; s) { cout &lt;&lt; s &lt;&lt; endl; } int main() { func(&quot;hello&quot;); // ✅ 正确:临时对象可以绑定到 const 引用 } ``` &gt; ✅ 这是最常用、最安全的做法。 --- ### 方法二:使用显式构造 + 左值(适合需要修改的情况) 如果你确实需要修改传入的字符串,你应该传递一个左值: ```cpp void func(string&amp; s) { s += &quot; world&quot;; } int main() { string s = &quot;hello&quot;; func(s); // ✅ 正确:s 是左值 cout &lt;&lt; s &lt;&lt; endl; // 输出 hello world } ``` --- ### 方法三:使用右值引用(C++11 及以上) 如果你希望专门处理临时对象(如移动语义场景),可以使用右值引用: ```cpp void func(string&amp;&amp; s) { cout &lt;&lt; s &lt;&lt; &quot; (rvalue)&quot; &lt;&lt; endl; } int main() { func(&quot;hello&quot;); // ✅ 正确:绑定到右值引用 } ``` &gt; 注意:这种方式适用于高级用途,比如资源管理或性能优化。 --- ## 🧪 常见出错场景汇总 | 场景 | 是否报错 | 原因 | |------|----------|------| | `func(&quot;hello&quot;)`,其中 `func(string&amp;)` | ❌ 报错 | 临时对象不能绑定到非 const 引用 | | `func(&quot;hello&quot;)`,其中 `func(const string&amp;)` | ✅ 正确 | 允许绑定到 const 引用 | | `func(string(&quot;abc&quot;))`,其中 `func(string&amp;)` | ❌ 报错 | 同样是一个临时对象 | | `func(s + &quot;abc&quot;)`,其中 `func(string&amp;)` | ❌ 报错 | 表达式结果是临时对象 | --- ## ✅ 总结处理流程: | 操作 | 描述 | |------|------| | ❌ 使用 `string&amp;` 接收临时对象 | 导致编译错误 | | ✅ 使用 `const string&amp;` 接收临时对象 | 安全、标准做法 | | ✅ 使用左值变量传递 | 需要修改内容时使用 | | ✅ 使用右值引用 `string&amp;&amp;` | 高级用途,如移动语义 | --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值