java 学习 方法参数按值传递和按引用传递:

    技术2022-05-20  41

    [list]

    按值传递:所谓按值传递就是在方法内部改变参数的值并不会影响传递进来的外部对象,例如: Java代码   int i = 1;   public void increment(int i){      i++;      System.out.println(i);   //输出为2   }   System.out.println(i);   //输出为1   int i = 1; public void increment(int i){ i++; System.out.println(i); //输出为2 } System.out.println(i); //输出为1 按引用传递:引用传递和按值传递相反,它会影响传递进来的外部对象(像C中的"&参数"就是按引用传递);

    [/list] 在Java只有按值传递,可能有人会奇怪传递进来如是对象,它会改变对象的值,例如:

    Java代码   public class Test{      int i;      public void increment(Test t){          t.i++;          System.out.println(i);   //输出为1      }      public static void main(String[] args){          Test t = new Test();          t.increment(t);          System.out.println(t.i); //输出也为1      }   }   public class Test{ int i; public void increment(Test t){ t.i++; System.out.println(i); //输出为1 } public static void main(String[] args){ Test t = new Test(); t.increment(t); System.out.println(t.i); //输出也为1 } }

    这的确是改变了对象的值,但它并没有改变对象引用的值,它还是指向原来的对象,我们传递进来的是对象引用并不是对象,造成这种错误的认识主要是没有理解对象和对象引用的区别,我们可以将对象理解为气球,而对象引用可理解为拉着气球的线,所以这还是按值传递; 1)"别名"问题:因为Java中只有按值传递,所以就会出现当有几个句柄(对象引用)指向同一对象时,有的可能需要改变对象的值,而有的并不需要,这就产生了别名问题,解决这一问题就是制作本地副本对象,通过Object.clone()方法,如下:

    Java代码        public class TestHandIn implements Cloneable {           private int in;           public void testreference(TestHandIn testin){      //制作本地副本,使其不影响外部对象       TestHandIn in = (TestHandIn)testin.clone();       in.in++;       System.out.println(in.in);//输出为1   }           public Object clone(){      Object obj = null;      try {        obj = super.clone();              } catch (CloneNotSupportedException e) {       System.out.println(e.getMessage());      }      return obj;   }           public static void main(String[] args){               TestHandIn in = new TestHandIn();               in.testreference(in);       System.out.println(in.in); //输出为0,没有改变           }        }   public class TestHandIn implements Cloneable { private int in; public void testreference(TestHandIn testin){ //制作本地副本,使其不影响外部对象 TestHandIn in = (TestHandIn)testin.clone(); in.in++; System.out.println(in.in);//输出为1 } public Object clone(){ Object obj = null; try { obj = super.clone(); } catch (CloneNotSupportedException e) { System.out.println(e.getMessage()); } return obj; } public static void main(String[] args){ TestHandIn in = new TestHandIn(); in.testreference(in); System.out.println(in.in); //输出为0,没有改变 } }

    clone()方法在Object中是protected的,子类要具有clone能力需覆盖此方法并实现Cloneable接口,这样做是为了不使每个类默认都具有clone能力,并且Object.clone()方法会检查该类是否实现了Cloneable接口,所以必须实现Cloneable接口; 2)只读类String及其"同志"类StringBuffer和StringBuilder:先看如下一段代码:

    Java代码   public void passString(String s){      s = s + "abc";      System.out.println(s);  //输出123abc   }   public static void main(String[] args){      String s = "123";      passString(s);      System.out.println(s);   //输出123,并没有改变   }   public void passString(String s){ s = s + "abc"; System.out.println(s); //输出123abc } public static void main(String[] args){ String s = "123"; passString(s); System.out.println(s); //输出123,并没有改变 }

    这好像看起来是按引用传递参数,其实是String类的作用,在String中的每个方法都是新建了个对象对其进行操作,所以原来对象并没有改变,String类也称只读类,它很好的解决了"别名问题",但如果需要一个修改的对象就很麻烦,同时有效率问题,于是出现了"同志"类StringBuffer和StringBuilder,StringBuffer是线程同步的,而StringBuilder不是,效率高些;StringBuffer和StringBuilder的append()方法修改不需要频繁创建对象,效率比"+"要高,但"+"看起来比较直观,根据实际情况选择:

    Java代码   String s = "abc";   s = s + "def" + "f" + "g" + "h";  //效率低    StringBuffer sb = new StringBuffer("abc");   sb.append("def").append("f").append("g").append("h"); //效率高   String s = "abc"; s = s + "def" + "f" + "g" + "h"; //效率低 StringBuffer sb = new StringBuffer("abc"); sb.append("def").append("f").append("g").append("h"); //效率高

    在String中比较有用的字符集转换方法:String.getBytes()和new String(byte[] bytes, String charsetName),在解决中文问题时非常有用的两个方法,字节流和字符流的转换桥梁类InputStreamReader和InputStreamWriter,底层实现就是使用这两个方法。


    最新回复(0)