黑马程序员技术交流社区

标题: 一些我以前不知道的基础 [打印本页]

作者: 闾丘日月    时间: 2012-6-6 08:38
标题: 一些我以前不知道的基础
昨天开始看java核心技术这本书,结果上来就雷了我一跳,好些知识我以前都不知道或者说误解的,罗列一些目前我遇到的问题。
1.syso(2.0-1.1)打印结果是0.8999999999999
2.public static void main(String\u005b\u005d args)这么写居然也行
3.1/0会发生异常而1.0/0不会发生异常
4.代码点和代码单元的知识,以及不建议在代码中处理char类型的数据
5.避免这样的设计  class A{private String str;
  public String getstr(){return str;}
  }  就是将私有对象的引用返回出去,这可能造成安全问题。
6.这个我想半天才想明白的,java里面所有的参数传递都是值传递。。不同于c++会有引用传递一说,下面是例子,a和b的值不会改变。
swap (String a, String b){
          String temp = a;
          a=b;
          b=temp;}

作者: 王月    时间: 2012-6-6 08:47
挺实用啊,lz多多分享哦
作者: 罗文杰    时间: 2012-6-6 08:56
{:3_66:}问下楼主,第5条会出现什么样的安全问题? 谢谢了~{:3_57:}
作者: 罗文杰    时间: 2012-6-6 09:34
虽然这样能拿到你的私有成员,但是只能使用,虽然利用反射方法可以修改,但是这安全问题只在用反射的时候产生么?还有比较迷糊,求楼主详解,万分感激,谢谢了~~~~
作者: 揭耀祖    时间: 2012-6-6 09:53
第六条我有不同的意见,java中基本类型是以值传递的,String类在参数传递时当作基本类型用,而类类型对象在参数传递时是以引用(也就是地址)传递的,这也就是为什么在java中没有复制构造函数的原因了。
public class test
{
   public static void main(String [] args)
    {
          StringBuffer sb = new StringBuffer("hello");
          System.out.println("change before..."+sb);
         change(sb);
         System.out.println("change after..."+sb);      
    }
    public static void change(StringBuffer str)
       {
          str.append("world");
       }
}

输出结果为:
changebefore...hello
changeafter...helloworld


作者: 闾丘日月    时间: 2012-6-6 22:50
罗文杰 发表于 2012-6-6 09:34
虽然这样能拿到你的私有成员,但是只能使用,虽然利用反射方法可以修改,但是这安全问题只在用反射的时候产 ...

注意到修改不用反射的。
String a = new String("abc");
String b=a;
如果b.substring();那么a的值同时也发生了变化,因为b指向的对象和a指向的对象是一样的。。都指向同一块堆区域也就是new出来的那个地址
作者: 闾丘日月    时间: 2012-6-6 22:58
本帖最后由 闾丘日月 于 2012-6-6 23:29 编辑
jxj4227982333 发表于 2012-6-6 09:53
第六条我有不同的意见,java中基本类型是以值传递的,String类在参数传递时当作基本类型用,而类类型对象在 ...


我以前也和你一样的困惑。但是确实是值传递,传递的地址也是一个值
在你的例子中,编译器新建了一个StringBuffer的引用比如说str,然后将sb的地址赋值给str
我们如果修改str确实可以达到修改sb所指向的内容的结果,但是sb的值是不会被修改的哦。
就是说sb永远指向你开始new出来的那个string的地址。
c++里的引用传递,可以通过修改str来修改sb那块内存中的地址值,可以让sb不指向那块内存
虽然两者看起来类似都可以修改sb指向的字符串,但是原理是不一样的。
我第6条给的测试代码如果是引用传递,那么传递进来的实参的值是可以互换的,
但是你可以试试这个函数能否起作用。
你也可以在你的测试代码之前和之后加入syso(sb.hashCode())来看看它的值是否有改变。我机器上的某次测试结果:
change before...hello
before hash..12677476
change after...helloworld
after hash..12677476
作者: 罗文杰    时间: 2012-6-6 23:20
闾丘日月 发表于 2012-6-6 22:50
注意到修改不用反射的。
String a = new String("abc");
String b=a;

晓得了,万分感谢:lol
作者: 揭耀祖    时间: 2012-6-8 10:25
你也可以在你的测试代码之前和之后加入syso(sb.hashCode())来看看它的值是否有改变。我机器上的某次测试结果:
change before...hello
before hash..12677476
change after...helloworld
after hash..12677476

你知道为什么两次hashCode()的值会相同么,不是因为它们的值相同,而是因为它们的地址值相同所以才会相等,也就是说两次hashCode()的调用返回的都是sb的地址值的hash码值,并不是sb地址中的内容值的hash码值,而sb指向的地址值始终都没有改变。我假设sb指向的地址是0xef,在调用change(StringBuffer )函数时,它的这个0xef地址值就就传给了str,然后str再把这个地址中的内容由"hello"变成"hello world",所以两次打印的hash码值相同并不是说sb指各的地址中的内容没有改变。
作者: 黑马罗坚    时间: 2012-6-8 11:14
地6条 JAVA中传递参数并不是把自身传递过去 而是把句柄的值传递过去  方法里的形参句柄把传递来的值赋给自己
String 虽然是引用类型   但是String类型的变量的值是不能被修改的  你在那个方法里修改的只是句柄的值  而不是句柄的值所对于的内存中的值。。。 所以原方法中的句柄的值和句柄的值所对应的内存中的值都是没变的。。。  即使你创建String时 是通过new String();也不行 因为即使这样修改的还是柄的值   即使用方法也不行因为它跟本不能通过方法修改内存中的值 只能修改句柄的值  而StringBuilder和其他引用类型的句柄的值所对应的内存的值是可以修改的  但是也不能通过sb=new StringBuilder();这种方式 这样修改的还是句柄的值只能通过调用方法的形式修改句柄所对应的堆内存的值  这样如果该方法没有加入同步块 就会造成线程安全问题 如StringBuilder  你可以手动添加同步块  也可以用StringBuffer 已经加入同步块的类型
作者: 赵玮_Tom    时间: 2012-6-10 20:00
闾丘日月 发表于 2012-6-6 22:50
注意到修改不用反射的。
String a = new String("abc");
String b=a;

楼主你好,我没看过Java核心技术这本书,但我有两个疑问:
1)第5条其实就是我们经常使用的setter方法呀
   class Person
    {
            private String name;
            public String getName()
            {
                     return name;
             }
    }
我们写程序不经常这样设计吗?
2)关于你说的String a = new String("abc"); String b = a; b.substring();我不是太明白。因为字符串是已经初始化就不会被改变的。

希望楼主解释,谢谢
作者: wxhuiuoa    时间: 2013-7-9 19:25
第五题那个  我觉得可以给str 一个get和set方法




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2