A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 梁小波 中级黑马   /  2012-6-7 19:14  /  2702 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

public boolean equals(Object obj)
        {

                if(!(obj instanceof Person))
                        return false;

                Person p = (Person)obj;
                System.out.println(this.name+"...equals.."+p.name);

                return this.name.equals(p.name) && this.age == p.age;
        }
在hashset的一段代码,视屏中有。
看到这段代码,有一个疑问?为什么 this.name.equals(p.name)可以执行?没有错误?注意name在该类中为private类型的!
而p是传入的一个参数。也就是p不是当前对象。怎么可以直接用p.name访问呢?难倒不该用getName()吗?
还是在该类的内部无论谁的对象(只要是该类的)都可以访问name字段;
不过请想一下:当你生成对象之后,p.name是在p对象中的。怎么可以在其他的对象方法中用p.name来访问?
不解,希望解释清楚一点!

评分

参与人数 1技术分 +1 收起 理由
职业规划-刘倩老师 + 1 赞一个!

查看全部评分

7 个回复

正序浏览
package cn.lwf.enhance2;

import java.util.*;
/*
往hashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。

*/
class HashSetTest
{
        public static void sop(Object obj)
        {
                System.out.println(obj);
        }
        public static void main(String[] args)
        {
                HashSet hs = new HashSet();
                hs.add(new Person("a1",11));
                hs.add(new Person("a2",12));
                hs.add(new Person("a3",13));
                hs.add(new Person("a2",12));
                hs.add(new Person("a4",14));

                //sop("a1:"+hs.contains(new Person("a2",12)));
                        
//                hs.remove(new Person("a4",13));
               

                Iterator it = hs.iterator();

                while(it.hasNext())
                {
                        Person p = (Person)it.next();
                        sop(p.getName()+"::"+p.getAge());
                }
        }
}
class Person
{
        private String name;
        private int age;
        Person(String name,int age)
        {
                this.name = name;
                this.age = age;
        }
        
        public int hashCode()
        {
                System.out.println(this.name+"....hashCode");
                return name.hashCode()+age*37;
        }

        @Override
        public boolean equals(Object obj)
        {
                if(!(obj instanceof Person))
                        return false;

                Person p = (Person)obj;
                System.out.println(this.name+"...equals.."+p.name);
               
                /**
                 * 下面使用的p2是 person实例,分别在getName()方法,getAge()方法下使用 p2.name都可以
                 * 说明在类中创建该类的实例对象都可以直接引用类中的私有域;
                 * 创建了外部类 Test继承Person;创建Test实例对象可以拿到t.name私有域;但是拿不到flag 私有域
                 * 说明在类中创建的子类实例对象可以直接引用构造父类Person的私有域;不能直接这样拿到子类特有的私有域;
                 * 创建内部类Test2,有私有域name,可以用t2.name直接拿到它;
                 * p.name 和p。getName() 它们的hash值都是一样的;
                 * 原理:参见《java核心技术 卷1 基础知识》 p153页;
                 * 如果一个方法没有被覆盖并且很短;编译器就能够对它进行优化处理,这个过程称为内联(inlining);例如:内联调用
                 * e.getName将会替换为访问e.name域;
                 * jvm中的即时编译器可以对一个可优化方法进行内联处理;
                 * 结论是:在类中创建的对象实例使用了内联处理;
                 * */
                Person p2 =new Person("abc",3);
                Person p3 =(Person)p2;
                System.out.println(p3.name.equals(p2.name));//True
               
                Person t = new Test("abc", 3);
                System.out.println(t.name.equals(p2.name));//false
               
                Test2 t2= new Test2(); //Test2是内部类;
                System.out.println(t2.name.equals(p2.name));//True

                //p.name 和p。getName() 它们的hash值都是一样的;
                System.out.println("p.name and p.getName() their hashcode is  "+(p.name.hashCode() == p.getName().hashCode()));
                return this.name.equals(p.name) && this.age == p.age;
               

        }
        
        //内部类
        class Test2{
                private String name= "abcd";
                private int age = 3;
        }

        
        public String getName()
        {
                //此处编译可以通过;
                Person p4 =new Person("abc",3);
                Person p5 =(Person)p4;
                p4.name.equals(p5.name);
               
                return name;

        }
        public int getAge()
        {        //此处编译可以通过;        
                Person p4 =new Person("a1",11);
            Person p5 =(Person)p4;
            p4.name.equals(p5.name);
                return age;
        }
        
        //编译通过;
        static{
                Person p4 =new Person("a1",11);
            Person p5 =(Person)p4;
            p4.name.equals(p5.name);
        }
}


class Test extends Person{
        private String name;
        private int age;
        private int flag = 9;
        Test(String name, int age) {
                super(name, age);
                this.name ="abcd";//拿不到该类name
                System.out.println(name);
                this.age =age;
                // TODO Auto-generated constructor stub
        }
}
回复 使用道具 举报
梁小波 发表于 2012-6-7 21:01
首先谢谢了,你的回答是解释的最清晰的,也最符合我的问题的;
你的意思是:java的封装是在建立这个对象 ...

你好,我现在在学校的图书馆上网,等下就得走了,宿舍的电脑没有联网,我想如果你不介意,我今晚回去验证下我的想法,现在的对这个问题的认识也比较浅薄。再给上我的解答。
回复 使用道具 举报
lz请注意一下类中有私有成员的原因是为了不让外部直接访问,而会对外提以供构造方法或者set、get方法的方式来允许外部访问,但却可以在内部被直接访问到。这就是封装的特点。所以p.name和p.age是可以实现的.

但是如果在这个类外,就必须通过构造方法或set、get方法的方式给name、age赋值,代码形式就是p.getName()、p.getAge()。
回复 使用道具 举报
李文富 发表于 2012-6-7 20:25
import java.util.*;
/*
往hashSet集合中存入自定对象

首先谢谢了,你的回答是解释的最清晰的,也最符合我的问题的;
你的意思是:java的封装是在建立这个对象的时候,禁止别的对象引用该类的private属性成员;那么我们要提供set,get方法;在本例中,p不是当前对象;但在编译的时候,源代码提供了这样的方式;也就是说只要是该对象的引用。在类代码中就可以用“.”访问属性!是吧?
回复 使用道具 举报
本帖最后由 李文富 于 2012-6-7 20:35 编辑

import java.util.*;
/*
往hashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。


*/
class HashSetTest
{
public static void sop(Object obj)
{
  System.out.println(obj);
}
public static void main(String[] args)
{
  HashSet hs = new HashSet();
  hs.add(new Person("a1",11));
  hs.add(new Person("a2",12));
  hs.add(new Person("a3",13));
//  hs.add(new Person("a2",12));
//  hs.add(new Person("a4",14));
  //sop("a1:"+hs.contains(new Person("a2",12)));
   
//  hs.remove(new Person("a4",13));
  
  Iterator it = hs.iterator();
  while(it.hasNext())
  {
   Person p = (Person)it.next();
   sop(p.getName()+"::"+p.getAge());
  }
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
  this.name = name;
  this.age = age;
}

public int hashCode()
{
  System.out.println(this.name+"....hashCode");
  return name.hashCode()+age*37;
}
public boolean equals(Object obj)
{
  if(!(obj instanceof Person))
   return false;
  Person p = (Person)obj;
  System.out.println(this.name+"...equals.."+p.name);
/**
*这里的equals方法是定义在person类的内部,getName(),getAge()是提供类的外部调用私有成员变量的方法,
*person p 是在类的内部引用外部obj传递过来的对象,p是设计在类的内部,
*所以p也可以直接引用私有成员变量。在这里你可以把p当成是指针,其实它就是个指针来的;
*把 "." 号读作是指向,这样就比较好理解一些;
*这里 在p引用自己指向对象的私有成员变量name ,并没有破坏类的封装性,是自己在自己内部建立起来的引用;
*/

  return this.name.equals(p.name) && this.age == p.age;
}

public String getName()
{
  return name;
}
public int getAge()
{
  return age;
}
}
/*
你说的应该是这个程序,希望能帮到你,可以一起讨论一下
*/

未命1111.JPG (30.37 KB, 下载次数: 28)

未命1111.JPG

评分

参与人数 1技术分 +2 收起 理由
职业规划-刘倩老师 + 2 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 王渠 于 2012-6-7 20:18 编辑

  1. public boolean equals(Object obj)
  2.         {

  3.                 if(!(obj instanceof Person))
  4.                         return false;

  5.                 Person p = (Person)obj;
  6.                 System.out.println(this.name+"...equals.."+p.name);

  7.                 return this.name.equals(p.name) && this.age == p.age;
  8.         }
复制代码
首先看equals(Object obj) ,可以接受Object对象,

if(!(obj instanceof Person))//这句话使得不可转成Person对象传入后,直接返回false;
return false;

Person p = (Person)obj; //既然满足了可以转成Person对象,那就可以进行强转成Person对象,

return this.name.equals(p.name) && this.age == p.age; //返回true的条件是名字和年龄都相符,说明调用该方法的也是Person对象,自然可以用name方法


回复 使用道具 举报
你这个是在person类中自己使用,所以私有的字段是可见的,能够通过对象名.字段来调用私有属性。在类的外部就不可以这样调用。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马