精华内容
下载资源
问答
  •   最近看到一道关于string的面试题,差点让我以为string是值传递,就是下面这个例子,体验下: 1 2 3 4 5 6 7 8 9 10 11 12 public class ...

    1.String中的坑

      最近看到一道关于string的面试题,差点让我以为string是值传递,就是下面这个例子,体验下:

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class demo{
        public static void main(string[] args) {
            demo d = new demo();
            string str = "bea";
            d.change(str);
            system.out.println(str);
        }
        void change(string s){
            s= s.replace('a''e');
            s = s.tolowercase();
        }
    }

      当时一看到这个题目,我第一反应就是输出”bee“,因为string是引用类型,其参数传递的方式就是引用传递,传递的是string的地址。可是答案让我的大吃一惊,“bea”,str根本就没有发生变化!!

      难道string是值传递?难道string是基本类型?

      其实都不是,后来通过查阅相应资料发现,jvm在实例化字符串时会使用字符串常量池,把str作为参数传入change()方法。jvm复制了一份str变量,为了便于理解我们叫它str'。这个时候str和str'都指向字符串常量池中的“abc”。

      当我们执行s = s.replace('a', 'e');
    其实相当于执行了s = new string(s.replace('a', 'e'));

     要理解上面这两段话,就要从java的底层结构说起了。java的内存模型大体分为  和  (细分还有方法区,和程序计数器等)。

    1.基本类型的变量放在栈里;

    2.封装类型中,对象放在堆里,对象的引用放在栈里。

    java在方法传递参数时,是将变量复制一份,然后传入方法体去执行。

    根据这些再细分一下jvm的执行过程

    1.虚拟机在堆中开辟一块内存,并存值”bea”。

    2.虚拟机在栈中分配给str一个内存,内存中存的是1中的地址。(1指第一步)

    3.虚拟机复制一份str,我们叫str’,str和str’内存不同,但存的值都是1的地址。

    4.将str’传入方法体

    5.方法体在堆中开辟一块内存,并存值”bee”。

    6.方法体在堆中再次开辟一块内存,并存值”bee”。

    7.方法体将str’的值改变,存入5的内存地址。

    8.方法结束,方法外打印str,由于str存的是1的地址,所有打印结果是”bea”。

    string的底层是一个不可变数据,所以每次给他赋新的值的时候都相当于新建了一个string对象(如果string常量池里没有该字符串的话),我们可以验证一下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class demo{
        public static void main(string[] args) {
            demo d = new demo();
            //通过比较str的hashcode来比较两个对象是否为同一对象
            string str = "bea";
            system.out.println("第一次string的hashcode:"+str.hashcode());
            str = "bee";
            system.out.println("第二次string的hashcode:"+str.hashcode());
            //stringbuilder来试一次
            stringbuilder s = new stringbuilder("bea");
            system.out.println("第一次stringbuilder的hashcode:"+s.hashcode());
            s.append('t');
            system.out.println("第二次stringbuilder的hashcode:"+s.hashcode());
            system.out.println("调用方法前的stringbuilder对象的值:"+s);
            d.change(s);
            system.out.println("调用方法后的stringbuilder对象的值:"+s);
        }
        void change(stringbuilder s){
            s = s.append('s');
        }
    }

      看看执行的结果~

    file

      tips: hashcode并不能判断是否为同一个对象,但是hashcode不同的话肯定不是同一个对象,hashcode相同的不一定是同一个对象。

    2.String str = "" 和 new String()的区别

    首先明白一个事,java存在一个常量池,可以用来存储字符串常量。

    1 创建的字符串变量在内存中的区别

    两者看似都是创建了一个字符串对象,但在内存中确是各有各的想法。

    String str1= “abc”; 在编译期,JVM会去常量池来查找是否存在“abc”,如果不存在,就在常量池中开辟一个空间来存储“abc”;如果存在,就不用新开辟空间。然后在栈内存中开辟一个名字为str1的空间,来存储“abc”在常量池中的地址值。

    String str2 = new String("abc") ;当使用String str=new String("abc");时,不管事先是否存在"abc",每次都会创建其新的对象。

    2 String类的特性

    String类 是final修饰的,不可以被继承。

    String类的底层是基于char数组的。

    3 两个方面

    1)性能效率

    String类被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。例如:

    String str = “hello";

    str = str + "world“;

    所以当上文str指向了一个String对象(内容为“hello”),然后对str进行“+”操作,str原来指向的对象并没有变,而是str又指向了另外一个对象(“hello world”),原来的对象还在内存中。

    由此也可以看出,频繁的对String对象进行修改,会造成很大的内存开销。此时应该用StringBuffer或StringBuilder来代替String。

    而new String()更加不适合,因为每一次创建对象都会调用构造器在堆中产生新的对象,性能低下且内存更加浪费。

    2)安全性

    对象都是只读的,所以多线程并发访问也不会有任何问题。

    由于不可变,用来存储数据也是极为安全的。

    展开全文
  • string与参数引用传递

    千次阅读 2017-04-04 16:14:56
    编者语:书上都说string是引用类型,但事实上我所看到的string和所谓的值类型没有什么区别,但通过看以下的文章,明白了: 1、string a="abc";之后,如果a="xy",则是a并没有改变内存中已经存在的"abc",而是又创建...

    编者语:书上都说string是引用类型,但事实上我所看到的string和所谓的值类型没有什么区别,但通过看以下的文章,明白了:

    1、string a="abc";之后,如果a="xy",则是a并没有改变内存中已经存在的"abc",而是又创建了另外一个实例。实际上相当于:string a=new String("abc");a=new String("xy");但如果是StringBuffer,则:StringBuffer a=new StringBuffer("abc"); 这是如果再想改变a,则:a.append("xy");值变为"abcxy",其中并没有new。

    2、以上中:string a="abc"; b=a; a="xy"; 则b还是"abc"。
    但如果是:StringBuffer a=new StringBuffer("abc"); StringBuffer b=a; a=a.append("xy");  则b变为:"abcxy"。

    3、虽然string确实是引用类型,但我想我还是基本把他看成是值类型,因为他引用的内存中的值并不会改变,也应该不会说当另外一个应用改变了内存中的值,从而会导致这个值的改变,不会的。但stringBuffer却可以。还有数组等。

    4、数据分为2种,一种是值类型,一种是引用类型。但方法的传递方式却是三种,默认的一般书上不写,即值传递(val),另外2种是:ref 和 out。

    5、事实上,所有的值类型数据包括所谓的引用类型的string,在值参数时,其方法中都无法不从根本上改变其本质,因为任何常用的赋值都省略了new .....。只有数组、StringBuffer以及其他类在改变其中的部分内容是可以不改变其本质,如stringbuffer.append()、intArray[2]=100等,要改变他们的本质好像只能用new的形式。这也是为何我们经常分不清string是否是引用类型,以及传递参数时的种种疑惑的根源。举个Array的例子:

     

    void  aa( int () array, int  x, string  z)
    {
      array[
    2]=array[2]+100;
       array
    =new int[]{5,6,7}

      x
    =100;
      z
    ="zz";
    }


    void  bb(  ref   int [] array , int  x, string  z)
    {
      array[
    2]=array[2]+100;
      array
    =new int[]{5,6,7}

      x
    =100;
      z
    ="zz";

    }


    int [] a = new   int []  {1,2,3} ;
    int  xx = 9 ;
    string  zy = " zy " ;

     

     那么上面的结论中,如果是第一aa方法,只有数组会改变其值,而且只会执行第一行命令,结果为103,但不会new,而变为{5,6,7}。在ref方法中,数组会变为{5,6,7},xx和zy也会变的。以上是我的心得。

    以下是在Java中的结论,应该也适用于C#吧。

    1. 声明是什么?
    String s = "Hello world!";

    许多人都做过这样的事情,但是,我们到底声明了什么?回答通常是:一个String,内容是“Hello world!”。这样模糊的回答通常是概念不清的根源。如果要准确的回答,一半的人大概会回答错误。
    这个语句声明的是一个指向对象的引用,名为“s”,可以指向类型为String的任何对象,目前指向"Hello world!"这个String类型的对象。这就是真正发生的事情。我们并没有声明一个String对象,我们只是声明了一个只能指向String对象的引用变量。所以,如果在刚才那句语句后面,如果再运行一句:

    String string = s;

    我们是声明了另外一个只能指向String对象的引用,名为string,并没有第二个对象产生,string还是指向原来那个对象,也就是,和s指向同一个对象。
    2. String类的特殊性
    1) String s1 = “Hello”;  //产生一个String ”Hello”对象,并产生该对象的一个别名s1来引用该对象
    String s2 = “Hello”;  //又产生一个别名s2来引用上面的”Hello”对象
    s1 == s2 = true;   //由于是同一个对象所以“==”返回为true
    s1 = “World”;  //产生一个String ”World”对象, s1的引用不再指向“Hello”而是指向对象”World”
    s1 == s2 = false;   //由于不是同一个对象所以“==”返回为false
    s1 = “Hello”;  //同上面的String s2 = “Hello”; 现在s1又指向对象”Hello”, 因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。
    s1 == s2 = true;   //由于是同一个对象所以“==”又返回为true了
    s1 = s1 + “World”;  //这时又产生一个对象”HelloWord”,s1不再指向”Hello”而是指向”HelloWord”
    s1 == s2 = false;  //不是一个对象当然是false拉
    s1 = s1+ "a"+"b"+"c"+…;  // String不停的创建对象,影响性能,这种易变的String用StringBuffer会得到更好的性能
    StringBuffer s3 = new StringBuffer(“Hello”); 
    s3.append(“a”); //没有生成新的对象,而是将s3引用的对象内容改为”Helloa”

    //说明: String类用来表示那些创建后就不会再改变的字符串,它是immutable的。而StringBuffer类用来表示内容可变的字符串,并提供了修改底层字符串的方法。
    StingBuffer是一个可变的字符串,它可以被更改。同时StringBuffer是Thread safe的, 你可以放心的使用.

    因为String被设计成一种安全的字符串, 避免了C/C++中的尴尬。因此在内部操作的时候会频繁的进行对象的交换, 因此它的效率不如StringBuffer。 如果需要频繁的进行字符串的增删操作的话最好用StringBuffer。 比如拼SQL文, 写共函。 另: 编绎器对String的+操作进行了一定的优化。 
    x = "a" + 4 + "c"
    会被编绎成
    x = new StringBuffer().append("a").append(4).append("c").toString()
    但:
    x = “a”;
    x = x + 4;
    x = x + “c”;
    则不会被优化。 可以看出如果在一个表达式里面进行String的多次+操作会被优化, 而多个表达式的+操作不会被优化。
    摘自:《Java API Using, Tips And Performance Tuning》
    2) Integer、Boolean等wrapper类以及BigInteger、BigDecimal是immutable的,所以也有与String类似的地方,不过没有IntegerBuffer之类的东西。不过Float, Double,Boolean比较特殊。如
    T a1 = 10; //T代指Byte,Integer,Short,Long
    T a2 = 10;
    if (f1 == f2)
     System.out.println(true);
    else
     System.out.println(false);
    这时总是true,和String有点类似

    T a1 = (T)10.0; //T代指Float,Double
    T a2 = (T)10.0;
    if (f1 == f2)
     System.out.println(true);
    else
     System.out.println(false);
    这时总是false

    Boolean a1 =true; 
    Boolean a2 =true;
    if (f1 == f2)
     System.out.println(true);
    else
     System.out.println(false);
    这时总是false
    总之如果比较两个Wrapper类的值用equals,以免不必要的麻烦
    3) 再看
    String s1 = new String(“Hello”);
    String s2 = new String(“Hello”);
    s1 == s2 = false;
    //因为new的时候JVM不管heap中有没有”Hello”对象都会产生一个新的”Hello”对象
    String s3 = “Hello”; //重新创建对象”Hello”, 并令s3指向对象”Hello”
    s3 == s1 = false; //不同对象当然false
    String s4 = “Hello”; 
    s3 == s4 = true;  //故伎重演,jvm清楚的知道哪些用了new,哪些没用new
    //Integer等整型wrapper类也有同样的特性
    3. 方法的参数传递中都是以reference传递,而primitive传递的是副本,但如果传递的是Integer、Boolean等wrapper类和String类的Object则是以immutable方式传递。示例:
    import java.awt.Point;
    class HelloWorld
    {
      public static void modifyPoint(Point pt, String j, int k, Integer m, Boolean b)
      {
        pt.setLocation(5,5);                                      
        j = "15";
        k = 25;
        m = 35;
        b = true;
        System.out.println("During modifyPoint " + "pt = " + pt +
                           " and j = " + j+ " and k = "+ k+ 
                           " and m = "+ m+ " and b = "+ b);
      }

      public static void main(String args[])
      {
        Point p = new Point(0,0);                                 
        String i = "10";
        int k = 20;
        Integer m = 30;
        Boolean b = false;
        System.out.println("Before modifyPoint " + "p = " + p +
                           " and i = " + i+ " and k = "+ k+ 
                           " and m = "+ m+ " and b = "+ b);
        modifyPoint(p, i, k, m, b);                                        
        System.out.println("After modifyPoint " + "p = " + p +
                           " and i = " + i+ " and k = "+ k+ 
                           " and m = "+ m+ " and b = "+ b);
      }
    }
    输出结果:
    Before modifyPoint p = java.awt.Point[x=0,y=0] and i = 10 and k = 20 and m = 30 and b = false
    During modifyPoint pt = java.awt.Point[x=5,y=5] and j = 15 and k = 25 and m = 35 and b = true
    After modifyPoint p = java.awt.Point[x=5,y=5] and i = 10 and k = 20 and m = 30 and b = false

     

     

     

     

    Java是传值还是传引用

    1. 简单类型是按值传递的

      Java 方法的参数是简单类型的时候,是按值传递的 (pass by value)。这一点我们可以通过一个简单的例子来说明:

    /* 例 1 */
    /**
     * @(#) Test.java
     * @author fancy
     */
    public class Test {
        public static void test(boolean test) {
            test = ! test;
            System.out.println("In test(boolean) : test = " + test);
        }
        public static void main(String[] args) {
            boolean test = true;
            System.out.println("Before test(boolean) : test = " + test);
            test(test);
            System.out.println("After test(boolean) : test = " + test);
        }
    }

      运行结果:

    Before test(boolean) : test = true
    In test(boolean) : test = false
    After test(boolean) : test = true

      不难看出,虽然在 test(boolean) 方法中改变了传进来的参数的值,但对这个参数源变量本身并没有影响,即对 main(String[]) 方法里的 test 变量没有影响。那说明,参数类型是简单类型的时候,是按值传递的。以参数形式传递简单类型的变量时,实际上是将参数的值作了一个拷贝传进方法函数的,那么在方法函数里再怎么改变其值,其结果都是只改变了拷贝的值,而不是源值。

      2. 什么是引用

      Java 是传值还是传引用,问题主要出在对象的传递上,因为 Java 中简单类型没有引用。既然争论中提到了引用这个东西,为了搞清楚这个问题,我们必须要知道引用是什么。

      简单的说,引用其实就像是一个对象的名字或者别名 (alias),一个对象在内存中会请求一块空间来保存数据,根据对象的大小,它可能需要占用的空间大小也不等。访问对象的时候,我们不会直接是访问对象在内存中的数据,而是通过引用去访问。引用也是一种数据类型,我们可以把它想象为类似 C 语言中指针的东西,它指示了对象在内存中的地址——只不过我们不能够观察到这个地址究竟是什么。

      如果我们定义了不止一个引用指向同一个对象,那么这些引用是不相同的,因为引用也是一种数据类型,需要一定的内存空间来保存。但是它们的值是相同的,都指示同一个对象在内存的中位置。比如

    String a = "Hello";
    String b = a;

      这里,a 和 b 是不同的两个引用,我们使用了两个定义语句来定义它们。但它们的值是一样的,都指向同一个对象 "Hello"。也许你还觉得不够直观,因为 String 对象的值本身是不可更改的 (像 b = "World"; b = a; 这种情况不是改变了 "World" 这一对象的值,而是改变了它的引用 b 的值使之指向了另一个 String 对象 a)。那么我们用 StringBuffer 来举一个例子:

    /* 例 2 */
    /**
     * @(#) Test.java
     * @author fancy
     */
    public class Test {
        public static void main(String[] args) {
            StringBuffer a = new StringBuffer("Hello");
            StringBuffer b = a;
            b.append(", World");
            System.out.println("a is " + a);
        }
    }

      运行结果:

    a is Hello, World

      这个例子中 a 和 b 都是引用,当改变了 b 指示的对象的值的时候,从输出结果来看,a 所指示的对象的值也改变了。所以,a 和 b 都指向同一个对象即包含 "Hello" 的一个 StringBuffer 对象。

      这里我描述了两个要点:
    1. 引用是一种数据类型,保存了对象在内存中的地址,这种类型即不是我们平时所说的简单数据类型也不是类实例(对象);
    2. 不同的引用可能指向同一个对象,换句话说,一个对象可以有多个引用,即该类类型的变量。

      3. 对象是如何传递的呢

      关于对象的传递,有两种说法,即“它是按值传递的”和“它是按引用传递的”。这两种说法各有各的道理,但是它们都没有从本质上去分析,即致于产生了争论。

      既然现在我们已经知道了引用是什么东西,那么现在不妨来分析一下对象作是参数是如何传递的。还是先以一个程序为例:

    /* 例 3 */
    /**
     * @(#) Test.java
     * @author fancy
     */
    public class Test {
        public static void test(StringBuffer str) {
            str.append(", World!");
        }
        public static void main(String[] args) {
            StringBuffer string = new StringBuffer("Hello");
            test(string);
            System.out.println(string);
        }
    }

      运行结果:

      Hello, World!

      test(string) 调用了 test(StringBuffer) 方法,并将 string 作为参数传递了进去。这里 string 是一个引用,这一点是勿庸置疑的。前面提到,引用是一种数据类型,而且不是对象,所以它不可能按引用传递,所以它是按值传递的,它么它的值究竟是什么呢?是对象的地址。

      由此可见,对象作为参数的时候是按值传递的,对吗?错!为什么错,让我们看另一个例子:

    /* 例 4 */
    /**
     * @(#) Test.java
     * @author fancy
     */
    public class Test {
        public static void test(String str) {
            str = "World";
        }
        public static void main(String[] args) {
            String string = "Hello";
            test(string);
            System.out.println(string);
        }
    }

      运行结果:

    Hello

      为什么会这样呢?因为参数 str 是一个引用,而且它与 string 是不同的引用,虽然它们都是同一个对象的引用。str = "World" 则改变了 str 的值,使之指向了另一个对象,然而 str 指向的对象改变了,但它并没有对 "Hello" 造成任何影响,而且由于 string 和 str 是不同的引用,str 的改变也没有对 string 造成任何影响,结果就如例中所示。

      其结果是推翻了参数按值传递的说法。那么,对象作为参数的时候是按引用传递的了?也错!因为上一个例子的确能够说明它是按值传递的。

      结果,就像光到底是波还是粒子的问题一样,Java 方法的参数是按什么传递的问题,其答案就只能是:即是按值传递也是按引用传递,只是参照物不同,结果也就不同。

      4. 正确看待传值还是传引用的问题

      要正确的看待这个问题必须要搞清楚为什么会有这样一个问题。

      实际上,问题来源于 C,而不是 Java。

      C 语言中有一种数据类型叫做指针,于是将一个数据作为参数传递给某个函数的时候,就有两种方式:传值,或是传指针,它们的区别,可以用一个简单的例子说明:

    /* 例 5 */
    /**
     * @(#) test.c
     * @author fancy
     */
    void SwapValue(int a, int b) {
        int t = a;
        a = b;
        b = t;
    }
    void SwapPointer(int * a, int * b) {
        int t = * a;
        * a = * b;
        * b = t;
    }
    void main() {
        int a = 0, b = 1;
        printf("1 : a = %d, b = %d/n", a, b);
        SwapValue(a, b);
        printf("2 : a = %d, b = %d/n", a, b);
        SwapPointer(&a, &b);
        printf("3 : a = %d, b = %d/n", a, b);
    }

      运行结果:

    1 : a = 0, b = 1
    2 : a = 0, b = 1
    3 : a = 1, b = 0

      大家可以明显的看到,按指针传递参数可以方便的修改通过参数传递进来的值,而按值传递就不行。

      当 Java 成长起来的时候,许多的 C 程序员开始转向学习 Java,他们发现,使用类似 SwapValue 的方法仍然不能改变通过参数传递进来的简单数据类型的值,但是如果是一个对象,则可能将其成员随意更改。于是他们觉得这很像是 C 语言中传值/传指针的问题。但是 Java 中没有指针,那么这个问题就演变成了传值/传引用的问题。可惜将这个问题放在 Java 中进行讨论并不恰当。

      讨论这样一个问题的最终目的只是为了搞清楚何种情况才能在方法函数中方便的更改参数的值并使之长期有效。

      Java 中,改变参数的值有两种情况,第一种,使用赋值号“=”直接进行赋值使其改变,如例 1 和例 4;第二种,对于某些对象的引用,通过一定途径对其成员数据进行改变,如例 3。对于第一种情况,其改变不会影响到方法该方法以外的数据,或者直接说源数据。而第二种方法,则相反,会影响到源数据——因为引用指示的对象没有变,对其成员数据进行改变则实质上是改变的该对象。

      5. 如何实现类似 swap 的方法

      传值还是传引用的问题,到此已经算是解决了,但是我们仍然不能解决这样一个问题:如果我有两个 int 型的变量 a 和 b,我想写一个方法来交换它们的值,应该怎么办?

      结论很让人失望——没有办法!因此,我们只能具体情况具体讨论,以经常使用交换方法的排序为例:

    /** 例 6 */
    /**
     * @(#) Test.java
     * @author fancy
     */
    public class Test {
        public static void swap(int[] data, int a, int b) {
            int t = data[a];
            data[a] = data[b];
            data[b] = t;
        }
        public static void main(String[] args) {
            int[] data = new int[10];
            for (int i = 0; i < 10; i++) {
                data[i] = (int) (Math.random() * 100);
                System.out.print(" " + data[i]);
            }
            System.out.println();
            for (int i = 0; i < 9; i++) {
                for (int j = i; j < 10; j++) {
                    if (data[i] > data[j]) {
                        swap(data, i, j);
                    }
                }
            }
            for (int i = 0; i < 10; i++) {
                System.out.print(" " + data[i]);
            }
            System.out.println();
        }
    }

      运行结果(情况之一):

    78 69 94 38 95 31 50 97 84 1
    1 31 38 50 69 78 84 94 95 97

      swap(int[] data, int a, int b) 方法在内部实际上是改变了 data 所指示的对象的成员数据,即上述讨论的第二种改变参数值的方法。希望大家能够举一反三,使用类似的方法来解决相关问题。

    这里增加其他的比较类型

    public static void main(String[] args) {
    float f= 100.0f;
    int x=100;
    Integer t=new Integer(100);
    Integer t1=new Integer(100);
    String s=new String("100");
    String s1=new String("100");
    String s3="100";
    System.out.println(s3==s);
    if(f==x){
    System.out.println("浮点数和整数比较的结果是true");
    }else{
    System.out.println("浮点数和整数比较的结果是false");


    }
    if(x==t){
    System.out.println("int型和Integer比较的结果是true");
    }else{
    System.out.println("int型和Integer比较的结果是false");


    }
    if(x==t1){
    System.out.println("int型和Integer比较的结果是true");
    }else{
    System.out.println("int型和Integer比较的结果是false");


    }
    if(t==t1){
    System.out.println("Integer和Integer比较的结果是true");
    }else{
    System.out.println("Integer和Integer比较的结果是false");


    }
    if(s!=s1){
    System.out.println("String 和String比较的结果是true");
    }else{
    System.out.println("String 和String比较的结果是false");


    }

    展开全文
  • java中String对象作为参数传递问题

    千次阅读 2020-06-03 15:24:04
    问题 java中将对象作为参数传递究竟是值传递还是引用传递? 1、基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值... String name; int age; } Student对象进行参数传递,运行如下代码 package

    问题

    java中将对象作为参数传递究竟是值传递还是引用传递?
    1、基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的。
    2、对象作为参数传递时,是把对象在内存中的地址拷贝了一份传给了参数。

    且看下面代码
    首先我们有一个Student类,它有两个成员变量nameage

    package test_code;
    public class Student {
        String name;
        int age;
        public Student(String name,int age){
            this.name = name;
            this.age = age;
        }
    }
    

    Student对象进行参数传递,运行如下代码

    package test_code;
    public class method_test {
        public static void main(String[] args) {
            Student s = new Student("jack",16);
            test(stu);
            System.out.println(stu.age);
        }
        public static void test(Student s)
        {
            s.age = 22;
        }
    }
    

    请问输出是16还是22呢?
    答案是22,因为对象进行参数传递时是将对象的地址拷贝了一份传给s,也就是说方法中的s和传入的stu指向的是同一个对象,通过s.age将值进行修改了那么stu.age的值也相应被修改了。这很容易理解。


    那么当String类对象进行参数传递时,运行如下代码

    package test_code;
    public class method_test {
        public static void main(String[] args) {
            String str = "111";
            test(str);
            System.out.println(str);
        }
        public static void test(String s)
        {
            System.out.println(s);
            s = "222";
            System.out.println(s);
        }
    }
    

    请问输出是什么呢?
    答案是222吗?不对。
    那么为什么答案是111呢?
    问题就在s = "222";这一行上。
    这一行执行后,s和str所指向的对象就不是一个了。为什么呢?
    由于Java中String对象不可改变的特性,这里其实是在常量池中新开辟了一块区域给222使用,s指向了222,但是并没有改变str的指向,那么str自然是111了。

    本文较为简单,但希望能够大家带来一定的启发,大家在工作学习中一定要多多思考,欢迎关注,一起进步。

    展开全文
  • dll传递string实现方法

    千次阅读 2015-12-30 18:03:57
    delphi中dll传递string的实现方法:  dll项目uses第一个引用sharemem单元;  调用的项目uses第一个引用sharemem单元;  调用的单元uses第一个引用sharemem单元;  **********************************************
     
    
    [delphi]  view plain copy
    1. delphi中dll传递string的实现方法:  
    2. dll项目uses第一个引用sharemem单元;  
    3. 调用的项目uses第一个引用sharemem单元;  
    4. 调用的单元uses第一个引用sharemem单元;  
    5. **************************************************************  

    最好是不要使用 string作Dll参数或返回值,用Pchar更好兼容非Delphi语言编程


    Delphi写DLL要注意的问题

    a. 参数和返回值为string、动态数组类型时,DLL和EXE都要把ShareMem作为.dpr工程的第一个单元引用。当然最好是不要使用 string、动态数组类型,可以改用PChar、数组指针类型,如果是混合语言编程使用的话,就一定不能用string、动态数组类型。这样做的原因是 DLL和EXE的内存管理器(MemoryManager)不是一个,而string、动态数组类型是通过引用计数由Delphi自动进行内存管理的,它 何时分配何时释放,我们不能显式的知道的,DLL分配而EXE释放的话,这样就出问题了。用ShareMem就是为了让它们统一使用一个内存管理器进行内 存分配释放。 关于DLL和EXE内存管理器不同这一点,非常重要! b.DLL和EXE的VCL类体系不是一个,它们各自有一套,因此,从EXE传递过去的对象,要在DLL中用is判断类型和as作类型转换,那都不能得到期望的结果。 如果是bpl,就不会有这个问题  c.DLL中应用ADO、窗体(模态、非模态、MDI子窗体)、线程等的一些相关问题与今天的主题关系不大,就不作多讲了。参考DLL的详细论述请参考《Windows核心编程》第19、20章。


    ========================================================


    对使用Delphi制作DLL复用文件的建议在公司里有一些需要制作DLL的场合,因为熟悉、方便和简易,大多数使用Delphi来制作。现在就这个主题提出一些个人建议。


    尽 量使用标准DLL接口。指的是传递的参数类型及函数返回类型不能是Delphi特有的,比如string(AnsiString),以及动态数组和含有这 些类型成员的复合类型(如记录),也不能是包含有这些类型成员数据成员的对象类型,以避免可能的错误。如果使用了string类型或动态数组类型,且调用 方不是Delphi程序,则基本上会报错。如果调用方是Delphi但调用方或被调用方没有在工程文件的第一包含单元不是ShareMem,也可能会出 错。


    如果调用方是Delphi应用程序,则可能可以使用不包含禁止类型(string, 动态数组)数据成员的对象作为参数或返回值,但也应尽量避免。


    如果调用方与被调用方都是Delphi程序,而且要使用string或动态数组作参数,则双方工程文件的第一包含单元必须是ShareMem。(C++Builder程序的情况可能与此相同,不过没有测试过。)


    如果调用方不是Delphi程序,则string、动态数组、包含string或动态数组的复合数据类型及类实例,都不能作为参数及返回值。


    因此,为了提高DLL的复用范围,避免可能存在的错误,应当使用标准WIN32 API标准参数类型,以前使用string的变量,可以使用PChar(s)转换。动态数组则转换为指针类型(@array[0]),并加上数组的长度。


    如果因为调用方与被调用方都是Delphi程序,为了编写方便,不想进行上述转换,则推荐使用运行时包的形式。运行时包可以保证动态分配数据的正确释放。这样因为其扩展名(.bpl),显出该文件仅限于Delphi/C++Builder使用(不象DLL)。


    其 次,尽量避免使用overload的函数/过程作输出,如果同一操作有多个方式,则可以让函数/过程名有少许差别,类似于Delphi中的 FormatXXXX、CreateXXXX等函数及方法,如CreateByDefaultFile, CreateDefault。


    最 后,作为DLL的提供者,应当提供直接编程的接口文件,如Delphi中的.pas或.dcu(最好是.pas,因为可以有注释)、C及C++中的.h 和.lib。而不是让使用者们自己创建。如果非要有overload的函数/过程,这一点显得特别重要。另外,作为Delphi应用,提供的.pas文件 可以是提前连接的(使用external指定DLL中的输出函数),也可以是后期连接的(使用LoadLibrary、 GetProcAddress),DLL提供者提供编程接口文件,既显得正式(或HiQoS),又有保障。
    展开全文
  • 1.普通传递 void f( int p){ printf("\n%x",&p); printf("\n%x",p); p=0xff; } void main() { int a=0x10; printf("\n%x",&a); printf("\n%x\n",a); f(a); printf("\n%x\n",a); } 2.引用传递 void f
  • stringstringstream用法

    万次阅读 多人点赞 2017-09-23 10:04:03
    stringstringstream用法总结
  • 解读GO语言中的值传递和引用传递

    千次阅读 2019-03-03 12:30:20
    GO语言在中的值传递和引用传递 GO语言中绝大部分类型都是基于值语义(值传递),包括: 基本类型:如byte、int、bool、float32、float64和string等; 复杂类型:如数组(array)、结构体(struct)、指针(pointer)...
  •  了解了这个经典问题,很多细心的读者肯定会立刻提出新的疑问:“可是String类型在Java语言中属于非基本类型啊!它在方法中的改变为什么没有被保存下来呢!”的确,这是个问题,而且这个新疑问几乎推翻了那个经典...
  • Java语言中的参数传递

    千次阅读 热门讨论 2007-12-31 11:49:00
    http://blog.csdn.net/mailbomb 在实际的开发过程中,方法调用是一种很常见的操作,在方法调用中,关于参数的处理可能很多进行实际开发的程序员都不一定理解的很清楚,下面系统的介绍一下Java语言中参数传递的规则...
  • 一、 最开始的示例 ...所以,在本文中首先以一个简单示例来抛出核心话题:public class StringAsParamOfMethodDemo {public static void main(String[] args) { StringAsParamOfMethodDemo StringAsParamOfMethodDe
  • //该方法定义在了 C 语言文件中 add ( 1 , 2 ) ; //2. 引用数据类型 //博客地址 : https://hanshuliang.blog.csdn.net/article/details/99239635 //代码 展示 流程 : //① 定义 普通 类型 变量 ...
  • 本文主要介绍 C++ 编程语言中值传递(pass-by-value)和引用传递(pass-by-reference)的相关知识。 1 值传递(pass-by-value) 在 C++ 编程语言中,一个函数在使用参数时,如果使用 pass-by-value 方式,那么编译...
  • JNI传递字符串数组J-StringArray

    千次阅读 2015-08-04 11:56:12
    编译器对语言的转换以寻地址的方式进行序列化和反序列化,因此对于不固定类型或者不显示给出大小的对象不能直接解析,所以没有出现jstringArray这样的类型,只能一个一个编写。  参考链接:安卓开发提高篇-Jarray ...
  • 回调函数传递字符串: Dll 端: typedef int (* pfCallBack )( int a , char b []); pfCallBack CallBackfun = NULL ;   extern "C" __declspec ( dllexport ) ...
  • 一句话总结:map、切片、接口、函数类型、chan都是引用类型,作为函数参数传递不会复制一个副本。 package main import ( "fmt" ) func change(a int) { a = 10 } func changeMap(m map[int]string)...
  • C#语言函数参数的传递

    千次阅读 2005-10-27 17:26:00
    C#语言函数参数的传递 就像C语言众多的后世子孙一样,C#的函数参数是非常讲究的。首先,参数必须写在函数名后面的括号里,这里我们有必要称其为形参。参数必须有一个参数名称和明确的类型声明。该参数名称只在函数...
  • C++引入的string类 C-风格字符串中有大量的函数用来操作以 null 结尾的字符串: 1 strcpy(s1,s2) 复制字符串 s2 到字符串 s1 2 strcat(s1,s2) 连接字符串 s2 到字符串 s1 的末尾 3 strlen(s1) 返回字符串 s1 的长度...
  • 可以理解为JNIEnv提供了一些列方法来完成JAVA与Native之间的数据转换与传递工作。 7.在Activity中布局一个TextView用来显示字符串,布局代码就不贴了。 @Override protected void onCreate(Bundle ...
  • 熟悉开发JNI基本流程以后,我来尝试写一下传递多种数据类型的情况。包括int、String、int[ ] 类型。这次我把这些native方法放在一个类中。 定义本地接口方法: package com.example.manzuo.jni; public class ...
  • 指针和参数传递(Go语言)

    千次阅读 2020-09-09 21:23:05
    指针 概述 指针是存储另一个变量的内存地址的变量 变量是一种使用方便的占位符,变量都指向计算机的内存...指针不能运算(不同于c语言) Go语言中如果对指针进行运算会报错 声明指针 *T是指针变量的类型,它指向T类
  • java基本数据类型传递与引用传递区别详解

    万次阅读 多人点赞 2016-04-19 17:12:57
    java的值传递和引用传递在面试中一般都会都被涉及到,今天我们就来聊聊这个问题,首先我们必须认识到这个问题一般是相对函数而言的,也就是java中的方法参数,那么我们先来回顾一下在程序设计语言中有关参数传递给...
  • String类型

    万次阅读 多人点赞 2018-08-25 16:50:03
    String类型 一、相关概念 1.定义 String类型是字符串的对象包装类型 创建String对象 var stringObject=new String(&amp;amp;amp;amp;quot;hello world&amp;amp;amp;amp;quot;); ...
  • 对于简单类型传值中涉及到string传递,本人的意见是:作为一个API,如果提供了某些功能,那么就必须实现,如果做不到或者不愿意做,就应该在编译期间断绝问题发生的可能( 就不应该让 Post(string a)、Post(string...
  • 进一步了解一下Lisp语言中函数的使用,虽然从这篇文章才开始介绍函数,但是我们在之前的Lisp文章中已经多次接触函数了。函数的定义在Lisp中函数的定义使用下面的格式:(defun function1 () (format *query-io* "in ...
  • 采用 lua_pushstring/lua_pushnumber 传递key、value,然后通过 lua_settable 设置 table 中的kv对,like this: lua_pushnumber(L, 1); lua_pushstring(L, "value1"); lua_settable(L, -3);
  • Java中是引用传递还是值传递

    千次阅读 多人点赞 2016-10-23 00:01:41
    前言在学习Java编程语言过程中最容易让你产生误解的问题之一就是 java是值传递还是引用传递。今天就来围绕这个话题揭开迷雾。概念首先先来认识一下什么是值传递什么是引用传递。- **值传递:**将方法实际参数值复制到...
  • public String nextLine():获取一个String类型的值 public String next():获取一个String类型的值 有个小问题,我们在获取了int类型的数据后,再去获取String类型的值会获取不到,这时候我们可以重新new一个对象 ...
  • 首先、我们必须牢记的一点是:java语言规范规定,String型变量指向的内存空间中的内容是不能被改变的,即String是不可改变的类!示例一:public class TestConstant{ public static void main(String args[]){...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 326,052
精华内容 130,420
关键字:

不同语言string传递