精华内容
下载资源
问答
  • Java对象的地址

    2013-06-13 10:14:41
    当你在论坛上讨论这一点,提出的第一个问题是为什么你需要知道Java对象的地址? 它是一种有效的问题。 但以往,我们保留进行试验的权利。探索未知领域的问题并没有什么错。我想出了一个使用sun公司包的实验。Unsafe...

    原文地址:http://javafans.info/java/corejava/15.html

      

    在传统的Java编程中,你将不再需要从内存中处理Java对象或位置。 当你在论坛上讨论这一点,提出的第一个问题是为什么你需要知道Java对象的地址? 它是一种有效的问题。 但以往,我们保留进行试验的权利。探索未知领域的问题并没有什么错。我想出了一个使用sun公司包的实验。Unsafe是一个属于sun.misc包。对你来说可能这个包有点陌生,看看源代码和方法,你就可以知道我所指的是什么了。

    Java的安全管理提供了足够的隐藏来确保你并不能那么容易的摆弄内存。作为第一步,我想到了要得到一个Java对象的内存位置。直到探索,我也曾经是100%的信心,这是不可能找到的位置 Java中对象的地址。

    Sun的Unsafe.java API文档显示我们有机会获得地址使用方法objectFieldOffset。这个方法仿佛在说:“报告中的类存储分配它的位置在一个特定领域。“ 它还说,“这只是其中一个访问器的cookie传递给不安全堆内存“。 无论如何,我能够从它的类的存储分配存储一个对象的内存位置。你可以争辩说,我们所得到的是不是一个对象的绝对物理内存地址。但是,我们拿到了逻辑内存地址。下面的程序将受到你的有趣!

    作为第一步,我得拿到Unsafe类的一个对象。这是很困难的,因为构造函数是私有的。 有一个名为getUnsafe一个方法,该方法返回不安全的对象。Java安全管理要求您给源代码特权。我用到了一点反射然后得到了一个实例。我知道有更好的方法来获得实例,但我选择了以下的方法来绕开安全管理。

    使用Unsafe的对象,只需要调用objectFieldOffset和staticFieldOffset。结果就是类的内存分配地址。

    以下的实例程序可以运行在JDK1.6上。

    
    import sun.misc.Unsafe;
    import java.lang.reflect.Field;
     
    public class ObjectLocation {
     
     private static int apple = 10;
     private int orange = 10;
     
     public static void main(String[] args) throws Exception {
      Unsafe unsafe = getUnsafeInstance();
     
      Field appleField = ObjectLocation.class.getDeclaredField("apple");
      System.out.println("Location of Apple: "
        + unsafe.staticFieldOffset(appleField));
     
      Field orangeField = ObjectLocation.class.getDeclaredField("orange");
      System.out.println("Location of Orange: "
        + unsafe.objectFieldOffset(orangeField));
     }
     
     private static Unsafe getUnsafeInstance() throws SecurityException,
       NoSuchFieldException, IllegalArgumentException,
       IllegalAccessException {
      Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
      theUnsafeInstance.setAccessible(true);
      return (Unsafe) theUnsafeInstance.get(Unsafe.class);
     }
    }
    
    展开全文
  • 如何获取到Java对象的地址

    万次阅读 2019-02-02 16:15:31
    final修饰实例时,表示该实例不可以被修改,但是具体是指实例内存地址不可以被修改? 还是实例里值不可以被修改?还是实例内存地址和值都不可以被修改? 其实是蛮简单一个问题,当fin...

    最近在整理final相关的测试用例,所以对final进行了重新思考,final 可以修饰类、方法、实例、参数!

    1. final修饰类时,表示该类不可以被继承
    2. final修饰方法时,表示该方法不可以被(子类)重写
    3. final修饰实例时,表示该实例不可以被修改,但是具体是指实例的内存地址不可以被修改? 还是实例里的值不可以被修改?还是实例的内存地址和值都不可以被修改?

    其实是蛮简单的一个问题,当final修饰到对象实例时, 表示什么意义,你有真正思考过吗?

    所以我写了一个测试类:

    import com.alibaba.fastjson.JSONObject;
    
    /**
     * final 修饰对象 
     * 
     * @author zhoufy
     * @date 2019年1月24日 下午6:35:26
     */
    public class FinalTest {
    	
    	public static void main(String[] args){
    		FinalTest t = new FinalTest();
    		t.test();
    	}
    	private void test(){
    		final Inner inner = new Inner();
    		print(inner);
    		inner.setId(1);
    		inner.setName("xiao ming");
    		print(inner);
    		inner.setId(2);
    		inner.setName("xiao hong");
    		print(inner);
    	}
    	
    	private void print(Inner inner){
    		System.out.println(inner.hashCode()+" : "+System.identityHashCode(inner)+" : "+JSONObject.toJSONString(inner));
    	}
    	
    	class Inner{
    		private int id;
    		private String name;
    		public int getId() {
    			return id;
    		}
    		public void setId(int id) {
    			this.id = id;
    		}
    		public String getName() {
    			return name;
    		}
    		public void setName(String name) {
    			this.name = name;
    		}
    	}
    }
    

    输出

    366712642 : 366712642 : {“id”:0}
    366712642 : 366712642 : {“id”:1,“name”:“xiao ming”}
    366712642 : 366712642 : {“id”:2,“name”:“xiao hong”}

    走到这里就已经证明了一点:final修饰的对象里的值是可以改变的,那地址呢? 而且还引起了我思考的一个问题haseCode()方法跟System.identityHashCode() 能代表对象的内存地址吗?

    先看一下haseCode()的源码:

    /**
     * Returns a hash code value for the object. This method is
     * supported for the benefit of hash tables such as those provided by
     * {@link java.util.HashMap}.
     * <p>
     * The general contract of {@code hashCode} is:
     * <ul>
     * <li>Whenever it is invoked on the same object more than once during
     *     an execution of a Java application, the {@code hashCode} method
     *     must consistently return the same integer, provided no information
     *     used in {@code equals} comparisons on the object is modified.
     *     This integer need not remain consistent from one execution of an
     *     application to another execution of the same application.
     * <li>If two objects are equal according to the {@code equals(Object)}
     *     method, then calling the {@code hashCode} method on each of
     *     the two objects must produce the same integer result.
     * <li>It is <em>not</em> required that if two objects are unequal
     *     according to the {@link java.lang.Object#equals(java.lang.Object)}
     *     method, then calling the {@code hashCode} method on each of the
     *     two objects must produce distinct integer results.  However, the
     *     programmer should be aware that producing distinct integer results
     *     for unequal objects may improve the performance of hash tables.
     * </ul>
     * <p>
     * As much as is reasonably practical, the hashCode method defined by
     * class {@code Object} does return distinct integers for distinct
     * objects. (This is typically implemented by converting the internal
     * address of the object into an integer, but this implementation
     * technique is not required by the
     * Java&trade; programming language.)
     *  * @return  a hash code value for this object.
     * @see     java.lang.Object#equals(java.lang.Object)
     * @see     java.lang.System#identityHashCode
      */
      public native int hashCode();
    

    这其中有几句话要细细斟酌

    • Returns a hash code value for the object. 返回对象的hash值
    • If two objects are equal according to the equals(Object) method, then calling the hashCode() method on each of the two objects must produce the same value. 如果两个对象相等(根据equals()方法判断),则hashCode()方法返回的值相同
    • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, developers should be aware that producing distinct integer results for unequal objects improves the performance of hash tables. 当equals()方法返回的不相等,则没有要求hashCode()方法必须返回不同的int值,但是开发人员应该为不相等的对象生成不同的整数结果,这样可以提高hash表的性能

    当看到这已经知道了hashCode()方法返回值不能代表对象的内存地址!!!

    顺便再看一下identityHashCode()方法的源码:

       /**
        * Returns the same hash code for the given object as
        * would be returned by the default method hashCode(),
        * whether or not the given object's class overrides
        * hashCode().
        * The hash code for the null reference is zero.
        *
        * @param x object for which the hashCode is to be calculated
        * @return  the hashCode
        * @since   JDK1.1
        */
       public static native int identityHashCode(Object x);
    

    从方法注释已经看出来,该方法默认返回的跟hashCode()方法同样的值

    如果查看jdk的源码:
    java.lang.System.java类对应的本地c语言的实现——System.c,在 openjdk-8u\jdk\src\share\native\java\lang 目录下

    JNIEXPORT jint JNICALL
    Java_java_lang_System_identityHashCode(JNIEnv *env, jobject this, jobject x)
    {
        return JVM_IHashCode(env, x);
    }
    

    java.lang.Object.java类对应的本地c语言的实现——Object.c,在 openjdk-8u\jdk\src\share\native\java\lang 目录下

    static JNINativeMethod methods[] = {
        {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
        {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
        {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
        {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
        {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
    };
    

    看jdk源说明hashCode()和identityHashCode() 调用的是同一个方法:JVM_IHashCode()
    所以两个方法返回的值相等就对了!

    那如何获取到Java对象的地址呢? 几经查询资料,原来还是有办法的,要通过sun.misc.Unsafe类来实现:

    package com.zhoufy.sun.unsafe.e3;
    
    public class A {
    	private long a;		// not initialized value
    	
    	public A() {
    		this.a = 1;		// initialization
    	}
    	
    	public long a() { return this.a; }
    }
    
    package com.zhoufy.sun.unsafe.e3;
    
    import java.lang.reflect.Field;
    import sun.misc.Unsafe;
    
    /**
     * @author zhoufy
     * @date 2019年2月2日 上午10:29:15
     */
    @SuppressWarnings("restriction")		//取消显示的警告集
    public class ObjectsAddressDemo {
    
    	static final Unsafe unsafe = getUnsafe();
    	static final boolean is64bit = true; // auto detect if possible.
    
    	public static void main(String... args) {
    		A a = new A();
    		
    		//GC前
    		System.out.println("-----------GC前------------");
    		print(a);
    		
    		System.gc();
    		
    		//GC后
    		System.out.println("-----------GC后------------");
    		print(a);
    	}
    
    	private static void print(A a) {
    		// hashcode
    		System.out.println("Hashcode :       " + a.hashCode());
    		System.out.println("Hashcode :       " + System.identityHashCode(a));
    		System.out.println("Hashcode (HEX) : " + Integer.toHexString(a.hashCode()));// Integer.toHexString(int)是将一个整型转成一个十六进制数
    
    		// toString
    		System.out.println("toString :       " + String.valueOf(a));
    
    		//通过sun.misc.Unsafe;
    		printAddresses("Address", a);
    	}
    
    	@SuppressWarnings("deprecation")
    	public static void printAddresses(String label, Object... objects) {
    		System.out.print(label + ":         0x");
    		long last = 0;
    		int offset = unsafe.arrayBaseOffset(objects.getClass());
    		int scale = unsafe.arrayIndexScale(objects.getClass());
    		switch (scale) {
    		case 4:
    			long factor = is64bit ? 8 : 1;
    			final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
    			System.out.print(Long.toHexString(i1));
    			last = i1;
    			for (int i = 1; i < objects.length; i++) {
    				final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
    				if (i2 > last)
    					System.out.print(", +" + Long.toHexString(i2 - last));
    				else
    					System.out.print(", -" + Long.toHexString(last - i2));
    				last = i2;
    			}
    			break;
    		case 8:
    			throw new AssertionError("Not supported");
    		}
    		System.out.println();
    	}
    
    	private static Unsafe getUnsafe() {
    		try {
    			Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    			theUnsafe.setAccessible(true);
    			return (Unsafe) theUnsafe.get(null);
    		} catch (Exception e) {
    			throw new AssertionError(e);
    		}
    	}
    }
    

    输出:

     -----------GC------------
    Hashcode :       1829164700
    Hashcode :       1829164700
    Hashcode (HEX) : 6d06d69c
    toString :       com.zhoufy.sun.unsafe.e3.A@6d06d69c
    Address:         0x76b4635b8
    -----------GC------------
    Hashcode :       1829164700
    Hashcode :       1829164700
    Hashcode (HEX) : 6d06d69c
    toString :       com.zhoufy.sun.unsafe.e3.A@6d06d69c
    Address:         0x6c1a0a338
    

    当然也可以通过jol工具包里的工具类实现获取对象的内存信息,使用jol工具包需要在maven里引入:

    <dependency>
    	<groupId>org.openjdk.jol</groupId>
    	<artifactId>jol-core</artifactId>
    	<version>0.9</version>
    </dependency>
    

    Java例子:

    package com.zhoufy.sun.unsafe.e3;
    
    import java.lang.reflect.Field;
    
    import org.openjdk.jol.info.GraphLayout;
    import org.openjdk.jol.vm.VM;
    
    import sun.misc.Unsafe;
    
    /** 
     * @author zhoufy
     * @date 2019年2月2日 上午10:29:15
     */
    @SuppressWarnings("restriction")		//取消显示的警告集
    public class ObjectsAddressDemo {
    
    	static final Unsafe unsafe = getUnsafe();
    	static final boolean is64bit = true; // auto detect if possible.
    
    	public static void main(String... args) {
    		A a = new A();
    		
    		//GC前
    		System.out.println("-----------GC前------------");
    		print(a);
    		
    		System.gc();
    		
    		//GC后
    		System.out.println("-----------GC后------------");
    		print(a);
    	}
    
    	private static void print(A a) {
    		//通过sun.misc.Unsafe;
    		printAddresses("Address", a);
    		
    		//通过jol工具包打印对象的地址
    		System.out.println(GraphLayout.parseInstance(a).toPrintable());
    		System.out.println("Current address: " + VM.current().addressOf(a));
    	}
    
    	@SuppressWarnings("deprecation")
    	public static void printAddresses(String label, Object... objects) {
    		System.out.print(label + ":         0x");
    		long last = 0;
    		int offset = unsafe.arrayBaseOffset(objects.getClass());
    		int scale = unsafe.arrayIndexScale(objects.getClass());
    		switch (scale) {
    		case 4:
    			long factor = is64bit ? 8 : 1;
    			final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
    			System.out.print(Long.toHexString(i1));
    			last = i1;
    			for (int i = 1; i < objects.length; i++) {
    				final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
    				if (i2 > last)
    					System.out.print(", +" + Long.toHexString(i2 - last));
    				else
    					System.out.print(", -" + Long.toHexString(last - i2));
    				last = i2;
    			}
    			break;
    		case 8:
    			throw new AssertionError("Not supported");
    		}
    		System.out.println();
    	}
    
    	private static Unsafe getUnsafe() {
    		try {
    			Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    			theUnsafe.setAccessible(true);
    			return (Unsafe) theUnsafe.get(null);
    		} catch (Exception e) {
    			throw new AssertionError(e);
    		}
    	}
    }
    

    输出:

    -----------GC------------
    Address:         0x76b463440
    com.zhoufy.sun.unsafe.e3.A@119d7047d object externals:
              ADDRESS       SIZE TYPE                       PATH                           VALUE
            76b463440         24 com.zhoufy.sun.unsafe.e3.A                                (object)
    
    
    Current address: 31864534080
    -----------GC------------
    Address:         0x6c1a0aab0
    com.zhoufy.sun.unsafe.e3.A@119d7047d object externals:
              ADDRESS       SIZE TYPE                       PATH                           VALUE
            6c1a0aab0         24 com.zhoufy.sun.unsafe.e3.A                                (object)
    
    
    Current address: 29018335920
    

    从输出信息来看,printAddresses()方法和jol工具类打印的对象的内存地址是一致的,当然如果去深入研究jol工具类,它底层也是通过sun.misc.Unsafe实现的!

    展开全文
  • java对象的地址引用及值引用

    千次阅读 2015-07-31 15:32:01
    所以当需要将一个list中的元素放到另外的list或其他集合中时,不能直接使用list 的get方法以及put方法,如果不需要对元素的进行内容的修改也可以,否则需要另外新建一个对象,并将原来的对象的内容赋值给新的对象。...

    当将一个list的元素分别保存到另外五个list中后,对5个list中的对象做值修改,其实这5个list的值会同时改变,所以当需要将一个list中的元素放到另外的list或其他集合中时,不能直接使用list 的get方法以及put方法,如果不需要对元素的进行内容的修改也可以,否则需要另外新建一个对象,并将原来的对象的内容赋值给新的对象。这将使用大量的get以及set方法,另外有两种办法可以直接对原有的对象进行克隆,可以避免大量的get以及set方法,生成一个原对象的副本。这时这两个对象的内容在内存地址是不一样的。

    当java 的不同方法获取同一个对象的地址引用,那任一方法都可以对这个对象内部进行修改,会对其他的引用造成影响。Java中所有的对象都是保存在堆中

    克隆有两种办法,一种是对pojo实现Cloneable接口

    public Object clone(){

       A  a  = null;

       try{

                a = (A) super.clone();

               }catch(Exception e){

                                   }

        return a;

    }


    当元素的属性包含了其他的vo 或数组时,上面的clone就对这种字段仍然是引用复制,也就是指这些字段的值都是同一个内存地址的。这时需要深度克隆,其实也就是在重载clone方法时,需要针对这些字段进行克隆


    public  Object  clone(){

              A   a  = null;

               try{

                          a = (A)super.clone();

                           a.name = (String[])name.clone();           

                               }catch(Exception e){

                                                                        }

    }



    另外一种克隆是将对象序列化,使用输出流以及输入流来进行克隆,这种克隆需要将对象以及内部引用的其他对象都进行序列化。


    public Object deepclone(){

       Object obj = null;

       try{

               ByteArrayOutputStream byout = new ByteArrayOutputStream();

               ObjectOutputStream obs = new ObjectOutputStream(byout);

                obs.writeObject(this);

                obs.close();

              ByteArrayInputStream byin  = new ByteArrayInputStream(byout.toByteArray());

              Object InputStream ibs = new ObjectInputStream(byin);

               obj = ibs.readOjbect();

               ibs.close();

                    }catch(Exception e){

                                  }

    }

    展开全文
  • 大家好,Java在创建对象时,在堆内存中分配到一块内存存储对象,而栈内存中的引用变量存储Java对象的地址,请问对象的首地址是如何分配的?对象的属性地址又是如何计算分配的?
  • 获得java对象的内存地址

    千次阅读 2018-10-24 12:17:31
    Java不能直接访问操作系统底层,而是通过本地方法来...要获得内存地址也只能通过Unsafe方法来获得,下面类提供了获取java对象内存地址的方法 package com.example.demo.othertest; import java.lang.reflect.Fi...

        Java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作,在java中内存中的对象地址是可变的,所以获得的内存地址有可能会变化。要获得内存地址也只能通过Unsafe的方法来获得,下面类提供了获取java对象内存地址的方法

    package com.example.demo.othertest;
    import java.lang.reflect.Field;
    import sun.misc.Unsafe;
    
    public class Addresser {
        private static Unsafe unsafe;
    
        static {
            try {
                Field field = Unsafe.class.getDeclaredField("theUnsafe");
                field.setAccessible(true);
                unsafe = (Unsafe) field.get(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static long addressOf(Object o) throws Exception {
    
            Object[] array = new Object[] { o };
    
            long baseOffset = unsafe.arrayBaseOffset(Object[].class);
            //arrayBaseOffset方法是一个本地方法,可以获取数组第一个元素的偏移地址
            int addressSize = unsafe.addressSize();
            long objectAddress;
            switch (addressSize) {
                case 4:
                    objectAddress = unsafe.getInt(array, baseOffset);
                    //getInt方法获取对象中offset偏移地址对应的int型field的值
                    break;
                case 8:
                    objectAddress = unsafe.getLong(array, baseOffset);
                    //getLong方法获取对象中offset偏移地址对应的long型field的值
                    break;
                default:
                    throw new Error("unsupported address size: " + addressSize);
            }
            return (objectAddress);
        }
    
        public static void main(String... args) throws Exception {
            Object mine = "Hello world".toCharArray(); //先把字符串转化为数组对象
            long address = addressOf(mine);
            System.out.println("Addess: " + address);
    
            // Verify address works - should see the characters in the array in the output
            printBytes(address, 27);
        }
    
        public static void printBytes(long objectAddress, int num) {
            for (long i = 0; i < num; i++) {
                int cur = unsafe.getByte(objectAddress + i);
                System.out.print((char) cur);
            }
            System.out.println();
        }
    }
    

     

    展开全文
  • 展开全部1、首先打开java构造方法代码。2、接下来就可以获得网卡物理地址方法代码。3、然32313133353236313431303231363533e4b893e5b19e31333431363639后得到获得机器IP地址方法代码。4、然后得到获得机器子网掩码...
  • Java对象存储地址

    千次阅读 2016-03-17 21:02:59
    Java程序运行时,对象时怎么进行放置安排?特别是内存是怎样分配?有六个不同地方可以存储数据: 1.寄存器(register):这是最快存储区,以为它位于不同于其他存储区地方——处理器内部,但是寄存器...
  • 如何获得java对象的内存地址

    万次阅读 2018-03-18 12:59:00
    java中内存中的对象地址是可变,所以获得内存地址有可能会变化。要获得内存地址也只能通过Unsafe方法来获得,如下代码片段:Java代码 package com.bijian.study; import java.lang.reflect.Field; ...
  • java对象的内存地址与hashcode值关系

    千次阅读 2020-05-19 12:44:57
    为了比较java对象的内存地址与hashcode的关系,必须想办法获取这两个值 Java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作,在java中内存中的对象地址是可变的,所以获得的...
  • Java打印对象的内存地址的示例代码 public static void main(String[] args) { String a = "11"; String b = new String("11"); System.out.println("a=b:" + a == b); System.out.println("a的内...
  • Java获取对象内存地址

    千次阅读 2020-10-09 21:50:38
    hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,获取对象散列的地址,并非实际内存地址。 java直接打印对象,结果是十六进制的散列地址值 public class ObjectTest { public static void main...
  • 使用sun.misc.Unsafe获取java对象地址

    千次阅读 2013-11-13 15:21:26
    当你在论坛上讨论这一点,提出的第一个问题是为什么你需要知道Java对象的地址? 它是一种有效的问题。 但以往,我们保留进行试验的权利。探索未知领域的问题并没有什么错。我想出了一个使用sun公司包的实验。Unsafe...
  • 结论:不是,hash code 只是Java 用来标识对象的,你可以形象的把它视为对象的身份证号码。 - 从对象.hashCode() 方法着手 官方API 的说法: 那具体实现是怎么样的? /** * Returns a hash code value for the ...
  • import java.util.ArrayList; import java.util.List; import java.util.Stack; import sun.misc.Unsafe; import java.util.Collections; import java.lang.reflect.Field; public static void main(String[] ...
  • JAVA获取对象内存地址

    千次阅读 2018-08-21 17:18:53
    为了观察JVM的GC过程中各个对象所处的位置,需要观察JVM各个对象的内存地址,与年轻代与老年代进行比对,确定对象位置。 package com.memory.tools; import sun.misc.Unsafe; import java.lang.reflect.Field; ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,846
精华内容 9,538
关键字:

java对象的地址

java 订阅