本文目錄一覽:
- 1、java中的怎麼比較兩個object值的大小
- 2、如何計算java中的對象object大小size
- 3、如何準確計算Java對象的大小
- 4、java中怎麼算一個對象的空間大小
- 5、如何計算java對象的大小
- 6、如何在java裡面對Object的類型值進行一個大小的比較
java中的怎麼比較兩個object值的大小
我給你舉個例子吧:創建一個熊貓類,實例化兩個熊貓對象,如果兩個對象的身高和年齡相同就認為這兩個對象的equals方法返回真,否則返回假
Panda類:
public class Panda {
double height;
int age;
@Override
public boolean equals(Object obj) {
if(this==obj){
return true;
}
if(obj instanceof Panda){
Panda panda=(Panda)obj;
if (this.height==panda.heightthis.age==panda.age){
return true;}
else{
return false;
}
}
return false;
}
}
Test類:
public class Test {
public static void main(String[] args) {
Panda panda=new Panda();
panda.height=1.60;
panda.age=4;
Panda panda1=new Panda();
panda1.height=1.60;
panda1.age=4;
System.out.println(panda.equals(panda1));
}
}
你可以測試一下。
如何計算java中的對象object大小size
// 利用GC回收前與回收後的差值計算對象的大小:
class Foo{ // 32位OS類定義引用佔8 byte,64位OS佔用16 byte
int x; // 4 byte
byte b; // 1 byte
}
public class Demo {
public static void main(String args[]) {
Foo foo= new Foo();
Runtime.getRuntime().gc();
long gcing = Runtime.getRuntime().freeMemory();
Foo foo2= new Foo();
long gced = Runtime.getRuntime().freeMemory();
// 64位打印24,32位打印16 (注:是因為JVM底層內存都是以8 byte對齊的,即8的倍數)
System.out.println(“Memory used:”+(gcing -gced ));
}
}
如何準確計算Java對象的大小
首先,我們先寫一段大家可能不怎麼寫或者認為不可能的代碼:一個類中,幾個類型都是private類型,沒有public方法,如何對這些屬性進行讀寫操作,看似不可能哦,為什麼,這違背了面向對象的封裝,其實在必要的時候,留一道後門可以使得語言的生產力更加強大,對象的序列化不會因為沒有public方法就無法保存成功吧,OK,我們簡單寫段代碼開個頭,逐步引入到怎麼樣去測試對象的大小,一下代碼非常簡單,相信不用我解釋什麼:
import java.lang.reflect.Field;
class NodeTest1 {
private int a = 13;
private int b = 21;
}
public class Test001 {
public static void main(String []args) {
NodeTest1 node = new NodeTest1();
Field []fields = NodeTest1.class.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
try {
int i = field.getInt(node);
field.setInt(node, i * 2);
System.out.println(field.getInt(node));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
代碼最基本的意思就是:實例化一個NodeTest1這個類的實例,然後取出兩個屬性,分別乘以2,然後再輸出,相信大家會認為這怎麼可能,NodeTest1根本沒有public方法,代碼就在這裡,將代碼拷貝回去運行下就OK了,OK,現在不說這些了,運行結果為:
26
42
為什麼可以取到,是每個屬性都留了一道門,主要是為了自己或者外部接入的方便,相信看代碼自己仔細的朋友,應該知道門就在:field.setAccessible(true);代表這個域的訪問被打開,好比是一道後門打開了,呵呵,上面的方法如果不設置這個,就直接報錯。
看似和對象大小沒啥關係,不過這只是拋磚引玉,因為我們首先要拿到對象的屬性,才能知道對象的大小,對象如果沒有提供public方法我們也要知道它有哪些屬性,所以我們後面多半會用到這段類似的代碼哦!
對象測量大小的方法關鍵為java提供的(1.5過後才有):java.lang.instrument.Instrumentation,它提供了豐富的對結構的等各方面的跟蹤和對象大小的測量的API(本文只闡述對象大小的測量方法),於是乎我心喜了,不過比較噁心的是它是實例化類:sun.instrument.IntrumentationImpl是sun開頭的,這個鬼東西有點不好搞,翻開源碼構造方法是private類型,沒有任何getInstance的方法,寫這個類幹嘛?看來這個只能被JVM自己給初始化了,那麼怎麼將它自己初始化的東西取出來用呢,唯一能想到的就是agent代理,那麼我們先拋開代理,首先來寫一個簡單的對象測量方法:
步驟1:(先創建一個用於測試對象大小的處理類)
import java.lang.instrument.Instrumentation;
public class MySizeOf {
private static Instrumentation inst;
/**
*這個方法必須寫,在agent調用時會被啟用
*/
public static void premain(String agentArgs, Instrumentation instP) {
inst = instP;
}
/**
* 直接計算當前對象佔用空間大小,包括:當前類及超類的基本類型實例字段大小
* 引用類型實例字段引用大小、實例基本類型數組總佔用空間、實例引用類型數組引用本身佔用空間大小
* 但是不包括超類繼承下來的和當前類聲明的實例引用字段的對象本身的大小、實例引用數組引用的對象本身的大小
* 用來測量java對象的大小(這裡先理解這個大小是正確的,後面再深化)
*/
public static long sizeOf(Object o) {
if(inst == null) {
throw new IllegalStateException(“Can not access instrumentation environment.\n” +
“Please check if jar file containing SizeOfAgent class is \n” +
“specified in the java’s \”-javaagent\” command line argument.”);
}
return inst.getObjectSize(o);
}
}
步驟2:上面我們寫好了agent的代碼,此時我們要將上面這個類編譯後打包為一個jar文件,並且在其包內部的META-INF/MANIFEST.MF文件中增加一行:Premain-Class: MySizeOf代表執行代理的全名,這裡的類名稱是沒有package的,如果你有package,那麼就寫全名,我們這裡假設打包完的jar包名稱為agent.jar(打包過程這裡簡單闡述,就不細說了),OK,繼續向下走:
步驟3:編寫測試類,測試類中寫:
public class TestSize {
public static void main(String []args) {
System.out.println(MySizeOf.sizeOf(new Integer(1)));
System.out.println(MySizeOf.sizeOf(new String(“a”)));
System.out.println(MySizeOf.sizeOf(new char[1]));
}
}
下一步準備運行,運行前我們準備初步估算下結果是什麼,目前我是在32bit模式下運行jvm(注意,不同位數的JVM參數設置不一樣,對象大小也不一樣大)。
(1) 首先看Integer對象,在32bit模式下,class區域佔用4byte,mark區域佔用最少4byte,所以最少8byte頭部,Integer內部有一個int類型的數據,佔4個byte,所以此時為8+4=12,java默認要求按照8byte對象對其,所以對其到16byte,所以我們理論結果第一個應該是16;
(2) 再看String,長度為1,String對象內部本身有4個非靜態屬性(靜態屬性我們不計算空間,因為所有對象都是共享一塊空間的),4個非靜態屬性中,有offset、count、hash為int類型,分別佔用4個byte,char value[]為一個指針,指針的大小在bit模式下或64bit開啟指針壓縮下默認為4byte,所以屬性佔用了16byte,String本身有8byte頭部,所以佔用了24byte;其次,一個String包含了子對象char數組,數組對象和普通對象的區別是需要用一個字段來保存數組的長度,所以頭部變成12byte,java中一個char採用UTF-16編碼,佔用2個byte,所以是14byte,對其到16byte,24+16=40byte;
(3) 第三個在第二個基礎上已經分析,就是16byte大小;
也就是理論結果是:16、40、16;
步驟4:現在開始運行代碼:運行代碼前需要保證classpath把剛才的agent.jar包含進去:
D:javac TestSize.java
D:java -javaagent:agent.jar TestSize
16
24
16
第一個和第三個結果一致了,不過奇怪了,第二個怎麼是24,不是40,怎麼和理論結果偏差這麼大,再回到理論結果中,有一個24曾經出現過,24是指String而不包含char數組的空間大小,那麼這麼算還真是對的,可見,java默認提供的方法只能測量對象當前的大小,如果要測量這個對象實際的大小(也就是包含了子對象,那麼就需要自己寫算法來計算了,最簡單的方法就是遞歸,不過遞歸一項是我不喜歡用的,無意中在一個地方看到有人用棧寫了一個代碼寫得還不錯,自己稍微改了下,就是下面這種了)。
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Stack;
public class MySizeOf {
static Instrumentation inst;
public static void premain(String agentArgs, Instrumentation instP) {
inst = instP;
}
public static long sizeOf(Object o) {
if(inst == null) {
throw new IllegalStateException(“Can not access instrumentation environment.\n” +
“Please check if jar file containing SizeOfAgent class is \n” +
“specified in the java’s \”-javaagent\” command line argument.”);
}
return inst.getObjectSize(o);
}
/**
* 遞歸計算當前對象佔用空間總大小,包括當前類和超類的實例字段大小以及實例字段引用對象大小
*/
public static long fullSizeOf(Object obj) {//深入檢索對象,並計算大小
MapObject, Object visited = new IdentityHashMapObject, Object();
StackObject stack = new StackObject();
long result = internalSizeOf(obj, stack, visited);
while (!stack.isEmpty()) {//通過棧進行遍歷
result += internalSizeOf(stack.pop(), stack, visited);
}
visited.clear();
return result;
}
//判定哪些是需要跳過的
private static boolean skipObject(Object obj, MapObject, Object visited) {
if (obj instanceof String) {
if (obj == ((String) obj).intern()) {
return true;
}
}
return (obj == null) || visited.containsKey(obj);
}
private static long internalSizeOf(Object obj, StackObject stack, MapObject, Object visited) {
if (skipObject(obj, visited)) {//跳過常量池對象、跳過已經訪問過的對象
return 0;
}
visited.put(obj, null);//將當前對象放入棧中
long result = 0;
result += sizeOf(obj);
Class ?clazz = obj.getClass();
if (clazz.isArray()) {//如果數組
if(clazz.getName().length() != 2) {// skip primitive type array
int length = Array.getLength(obj);
for (int i = 0; i length; i++) {
stack.add(Array.get(obj, i));
}
}
return result;
}
return getNodeSize(clazz , result , obj , stack);
}
//這個方法獲取非數組對象自身的大小,並且可以向父類進行向上搜索
private static long getNodeSize(Class ?clazz , long result , Object obj , StackObject stack) {
while (clazz != null) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers())) {//這裡拋開靜態屬性
if (field.getType().isPrimitive()) {//這裡拋開基本關鍵字(因為基本關鍵字在調用java默認提供的方法就已經計算過了)
continue;
}else {
field.setAccessible(true);
try {
Object objectToAdd = field.get(obj);
if (objectToAdd != null) {
stack.add(objectToAdd);//將對象放入棧中,一遍彈出後繼續檢索
}
} catch (IllegalAccessException ex) {
assert false;
}
}
}
}
clazz = clazz.getSuperclass();//找父類class,直到沒有父類
}
return result;
}
}
java中怎麼算一個對象的空間大小
Object流
直接將Object寫入或讀出
也叫做對象的序列化:把一個Object直接轉換成字節流寫到硬盤上,或者直接寫到網絡上去
這裡有一個類T:
class T implements Serializable { // 注意,必須要實現Serializable接口,才是可序列化的
int i = 10;
int j = 9;
double d = 2.3;
int k = 15;
}
這個類裡面的成員變量3個int,1個double,int是4字節,double是8字節
所以對象的大小絕對不會小於20字節,但是T肯定是從Object類繼承,那麼繼承下來這些內容也
占空間,比如方法什麼的,所以肯定要大於20字節了
運行下面這個類:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Test {
public static void main(String[] args) {
T t = new T();
try {
FileOutputStream fos = new FileOutputStream(“d:/abc.txt”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(t);
oos.flush();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
直接將T對象通過Object流寫到了D盤的名為abc.txt的文件裡面
一個空文本文件是0字節,找到這個文件以後查看它的屬性,我這裡是67 字節,
那麼這個對象就是67 字節
現在在T類中添加一些其他內容,那麼再次輸出,字節數肯定就比原來大了,它就是把整個對象轉換成
字節,寫入了文件,這個應該算是比較好的方式了,但是我們無法特別精確的知道對象中哪些內容各自
佔用多少空間,因為那是Java虛擬機的事了,我學的沒那麼深入,水平有限
當然,把一個對象寫進去,也可以讀出來:
FileInputStream fis = new FileInputStream(“”);
ObjectInputStream ois = new ObjectInputStream(fis);
// 當成Object讀出來的,強轉成T類型
T tReaded = (T)ois.readObject();
System.out.println(tReaded.i + ” ” + tReaded.j + ” ” + tReaded.d + ” ” + tReaded.k);
發現打印出的成員變量的值,還是存進去這個對象的值
如何計算java對象的大小
首先,我們先寫一段大家可能不怎麼寫或者認為不可能的代碼:一個類中,幾個類型都是private類型,沒有public方法,如何對這些屬性進行讀寫操作,看似不可能哦,為什麼,這違背了面向對象的封裝,其實在必要的時候,留一道後門可以使得語言的生產力更加強大,對象的序列化不會因為沒有public方法就無法保存成功吧,OK,我們簡單寫段代碼開個頭,逐步引入到怎麼樣去測試對象的大小,一下代碼非常簡單,相信不用我解釋什麼:
import java.lang.reflect.Field;
class NodeTest1 {
private int a = 13;
private int b = 21;
}
public class Test001 {
public static void main(String []args) {
NodeTest1 node = new NodeTest1();
Field []fields = NodeTest1.class.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
try {
int i = field.getInt(node);
field.setInt(node, i * 2);
System.out.println(field.getInt(node));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
代碼最基本的意思就是:實例化一個NodeTest1這個類的實例,然後取出兩個屬性,分別乘以2,然後再輸出,相信大家會認為這怎麼可能,NodeTest1根本沒有public方法,代碼就在這裡,將代碼拷貝回去運行下就OK了,OK,現在不說這些了,運行結果為:
26
42
為什麼可以取到,是每個屬性都留了一道門,主要是為了自己或者外部接入的方便,相信看代碼自己仔細的朋友,應該知道門就在:field.setAccessible(true);代表這個域的訪問被打開,好比是一道後門打開了,呵呵,上面的方法如果不設置這個,就直接報錯。
看似和對象大小沒啥關係,不過這只是拋磚引玉,因為我們首先要拿到對象的屬性,才能知道對象的大小,對象如果沒有提供public方法我們也要知道它有哪些屬性,所以我們後面多半會用到這段類似的代碼哦!
對象測量大小的方法關鍵為java提供的(1.5過後才有):java.lang.instrument.Instrumentation,它提供了豐富的對結構的等各方面的跟蹤和對象大小的測量的API(本文只闡述對象大小的測量方法),於是乎我心喜了,不過比較噁心的是它是實例化類:sun.instrument.IntrumentationImpl是sun開頭的,這個鬼東西有點不好搞,翻開源碼構造方法是private類型,沒有任何getInstance的方法,寫這個類幹嘛?看來這個只能被JVM自己給初始化了,那麼怎麼將它自己初始化的東西取出來用呢,唯一能想到的就是agent代理,那麼我們先拋開代理,首先來寫一個簡單的對象測量方法:
步驟1:(先創建一個用於測試對象大小的處理類)
import java.lang.instrument.Instrumentation;
public class MySizeOf {
private static Instrumentation inst;
/**
*這個方法必須寫,在agent調用時會被啟用
*/
public static void premain(String agentArgs, Instrumentation instP) {
inst = instP;
}
/**
* 直接計算當前對象佔用空間大小,包括:當前類及超類的基本類型實例字段大小
* 引用類型實例字段引用大小、實例基本類型數組總佔用空間、實例引用類型數組引用本身佔用空間大小
* 但是不包括超類繼承下來的和當前類聲明的實例引用字段的對象本身的大小、實例引用數組引用的對象本身的大小
* 用來測量java對象的大小(這裡先理解這個大小是正確的,後面再深化)
*/
public static long sizeOf(Object o) {
if(inst == null) {
throw new IllegalStateException(“Can not access instrumentation environment.\n” +
“Please check if jar file containing SizeOfAgent class is \n” +
“specified in the java’s \”-javaagent\” command line argument.”);
}
return inst.getObjectSize(o);
}
}
步驟2:上面我們寫好了agent的代碼,此時我們要將上面這個類編譯後打包為一個jar文件,並且在其包內部的META-INF/MANIFEST.MF文件中增加一行:Premain-Class: MySizeOf代表執行代理的全名,這裡的類名稱是沒有package的,如果你有package,那麼就寫全名,我們這裡假設打包完的jar包名稱為agent.jar(打包過程這裡簡單闡述,就不細說了),OK,繼續向下走:
步驟3:編寫測試類,測試類中寫:
public class TestSize {
public static void main(String []args) {
System.out.println(MySizeOf.sizeOf(new Integer(1)));
System.out.println(MySizeOf.sizeOf(new String(“a”)));
System.out.println(MySizeOf.sizeOf(new char[1]));
}
}
如何在java裡面對Object的類型值進行一個大小的比較
作者:Tao Li
鏈接:
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
java中類的比較一般有兩種方法,一種就是類本身實現ComparableT這個接口,比如通過對用戶的姓名進行比較排序:
package com.ailot.compare;
public class User implements ComparableUser {
private String name;
private int age;
private String sex;
public User(String name,int age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return “User [name=” + name + “, age=” + age + “, sex=” + sex + “]”;
}
@Override
public int compareTo(User u) {
// TODO Auto-generated method stub
int c = this.name.compareTo(u.name);
if(c==0){
return 0;
}else if(c 0){
return 1;
}else{
return -1;
}
}
}
Test.java
package com.ailot.compare;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class Test {
public static void main(String[] args) {
ListUser userList = new ArrayListUser();
for(int i=0;i10;i++){
int s = new Random().nextInt(20);
User u = new User(s+”張三”,i,”男”);
userList.add(u);
}
Collections.sort(userList);
for(User user : userList){
System.out.println(user.toString());
}
}
}
排序的話直接用 Collections.sort( userList ) ;就可以了。
作者:Tao Li
鏈接:
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
另一種就是類沒有實現ComparableT這個接口,這就需要自己新建一個比較的類,通過實現ComparatorT來對類進行比較,還是對User類的姓名進行比較排序:
User.java
package com.ailot.compare;
public class User {
private String name;
private int age;
private String sex;
public User(String name,int age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return “User [name=” + name + “, age=” + age + “, sex=” + sex + “]”;
}
}
UserCompare.java
package com.ailot.compare;
import java.util.Comparator;
public class UserCompare implements ComparatorUser {
@Override
public int compare(User u1, User u2) {
// TODO Auto-generated method stub
int c = u1.getName().compareTo(u2.getName());
if(c == 0){
return 0;
}else if(c 0){
return -1;
}else{
return 1;
}
}
}
Test.java
package com.ailot.compare;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class Test {
public static void main(String[] args) {
ListUser userList = new ArrayListUser();
for(int i=0;i10;i++){
int s = new Random().nextInt(20);
User u = new User(s+”張三”,i,”男”);
userList.add(u);
}
Collections.sort(userList,new UserCompare());
for(User user : userList){
System.out.println(user.toString());
}
}
}
排序的話直接用 Collections.sort(userList,new UserCompare());就可以了。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/298152.html