吃透Java基础五:Class类和Object类

2024-09-03 01:48
文章标签 java 基础 object class 吃透

本文主要是介绍吃透Java基础五:Class类和Object类,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在Java的世界里,一切皆是对象,所有的对象都是继承于Object类,而记录对象的类型的信息是由Class类来完成的,下面就让我们来具体了解一下Class类和Object类。

一:Class类

每个类的运行时的类型信息就是用Class对象表示的,它包含了与类有关的信息,其实我们的实例对象就通过Class对象来创建的。Java使用Class对象执行其RTTI(运行时类型识别,Run-Time Type Identification),多态是基于RTTI实现的。

每一个类都有Class对象,基本类型 ( byte, char, short, int, long, float, double and boolean)有Class对象,数组有Class对象,就连关键字void也有Class对象(void.class),Class对象对应着java.lang.Class类,如果说类是对象抽象和集合的话,那么Class类就是对类的抽象和集合。

Class类没有公共的构造方法,Class对象是在类加载的时候由Java虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。一个类被加载到内存并供我们使用需要经历如下三个阶段:

  • 加载:“加载”是“类加载”过程的第一个阶段,在加载阶段,虚拟机主要完成以下3件事情。
    1、通过一个类的全限定名来获取定义此类的二进制字节流。
    2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
    3、在内存中生成一个代表类的 java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

  • 链接:链接可以分为 验证、准备、解析 三个阶段
    验证:为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全,包括 文件格式验证、元数据验证、字节码验证、符号引用验证
    准备:准备阶段是正式为类变量(静态变量)分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。
    解析:解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,包括 类或接口的解析、字段解析、类方法解析、接口方法解析

  • 初始化:初始化阶段是执行类构造器()方法的过程,()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的。静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。

什么时候触发类的加载,请参考上一篇文章:吃透Java基础三:触发类初始化的五种方式

获取Class对象的三种方式

  1. Class.forName(“类的全限定名”)
  2. 实例对象.getClass()
  3. 类名.class (类字面常量)

Class类重要方法

类信息
私有构造函数,表示外部不能创建,只能由虚拟机默认去创建。

public final class Class<T> implements java.io.Serializable,GenericDeclaration,Type,AnnotatedElement {/** 私有构造函数,只能由虚拟机去创建*/private Class(ClassLoader loader) {classLoader = loader;}public String toString() {return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))+ getName();}}

通过forName()方法获取一个类的Class信息

/*** 返回与给定字符串名称的类或接口相关联的类对象*/
public static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);}/*** 使用给定的类加载器返回与给定字符串名称的类或接口相关联的类对象*/
public static Class<?> forName(String name, boolean initialize,ClassLoader loader)throws ClassNotFoundException{Class<?> caller = null;SecurityManager sm = System.getSecurityManager();if (sm != null) {// Reflective call to get caller class is only needed if a security manager// is present.  Avoid the overhead of making this call otherwise.caller = Reflection.getCallerClass();if (sun.misc.VM.isSystemDomainLoader(loader)) {ClassLoader ccl = ClassLoader.getClassLoader(caller);if (!sun.misc.VM.isSystemDomainLoader(ccl)) {sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);}}}return forName0(name, initialize, loader, caller);}/****/
private static native Class<?> forName0(String name, boolean initialize,ClassLoader loader,Class<?> caller)throws ClassNotFoundException;

通过newInstance可以创建一个该类的新的实例化对象

public T newInstance()throws InstantiationException, IllegalAccessException{if (System.getSecurityManager() != null) {checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);}// NOTE: the following code may not be strictly correct under// the current Java memory model.// Constructor lookupif (cachedConstructor == null) {if (this == Class.class) {throw new IllegalAccessException("Can not call newInstance() on the Class for java.lang.Class");}try {Class<?>[] empty = {};final Constructor<T> c = getConstructor0(empty, Member.DECLARED);// Disable accessibility checks on the constructor// since we have to do the security check here anyway// (the stack depth is wrong for the Constructor's// security check to work)java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {public Void run() {c.setAccessible(true);return null;}});cachedConstructor = c;} catch (NoSuchMethodException e) {throw (InstantiationException)new InstantiationException(getName()).initCause(e);}}Constructor<T> tmpConstructor = cachedConstructor;// Security check (same as in java.lang.reflect.Constructor)int modifiers = tmpConstructor.getModifiers();if (!Reflection.quickCheckMemberAccess(this, modifiers)) {Class<?> caller = Reflection.getCallerClass();if (newInstanceCallerCache != caller) {Reflection.ensureMemberAccess(caller, this, null, modifiers);newInstanceCallerCache = caller;}}// Run constructortry {return tmpConstructor.newInstance((Object[])null);} catch (InvocationTargetException e) {Unsafe.getUnsafe().throwException(e.getTargetException());// Not reachedreturn null;}}

二:Object类

Java中所有对象默认继承Object类,可以说,Object类是所有对象的祖先。Object类中一共定义12个方法,其中7个native方法,5个普通方法。

public class Object {private static native void registerNatives();static {registerNatives();}public final native Class<?> getClass();public native int hashCode();protected native Object clone() throws CloneNotSupportedException;public final native void wait(long timeout) throws InterruptedException;public final native void notify();public final native void notifyAll();public boolean equals(Object obj) {return (this == obj);}public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());}protected void finalize() throws Throwable { }public final void wait(long timeout, int nanos) throws InterruptedException {if (timeout < 0) {throw new IllegalArgumentException("timeout value is negative");}if (nanos < 0 || nanos > 999999) {throw new IllegalArgumentException("nanosecond timeout value out of range");}if (nanos > 0) {timeout++;}wait(timeout);}public final void wait() throws InterruptedException {wait(0);}
}

registerNatives()
registerNatives函数前面有native关键字修饰,Java中,用native关键字修饰的函数表明该方法的实现并不是在Java中去完成,而是由C/C++去完成,并被编译成了.dll,由Java去调用。

getClass()
getClass()也是一个native方法,返回的是此Object对象的类对象/运行时类对象Class<?>。效果与Object.class相同

hashCode()
返回对象的哈希码值。 支持这种方法是为了散列表,如HashMap提供的那样 。

  • 只要在执行Java应用程序时多次在同一个对象上调用该方法, hashCode方法必须始终返回相同的整数
  • 如果根据equals(Object)方法两个对象相等,则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果。
  • 不要求如果两个对象根据equals(java.lang.Object)方法不相等,那么在两个对象中的每个对象上调用hashCode方法必须产生不同的整数结果。 但是,程序员应该意识到,为不等对象生成不同的整数结果可能会提高哈希表的性能。

clone()
clone方法实现的是浅拷贝,只拷贝当前对象,并且在堆中分配新的空间,放这个复制的对象。但是对象如果里面有其他类的子对象,那么就不会拷贝到新的对象中。
深拷贝与浅拷贝

浅拷贝
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),
拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。
深拷贝相比于浅拷贝速度较慢并且花销较大。
现在为了要在clone对象时进行深拷贝, 那么就要Clonable接口,覆盖并实现clone方法,
除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。
如果只是用Object中默认的clone方法,是浅拷贝的。

wait() notify() notifAll()

wait():调用此方法所在的当前线程等待,直到在其他线程上调用此对象的notify()/notifyAll()方法。

wait(long timeout)/wait(long timeout, int nanos):调用此方法所在的当前线程等待,直到在其他线程上调用此对象的notify()/notifyAll()方法,或超过指定的超时时间量。

notify()/notifyAll():唤醒在此对象监视器上等待的单个线程/所有线程。

equals(Object obj)

判断两个对象是否相等,equals方法在非空对象引用上实现等价关系:

  • 自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
  • 对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。
  • 传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后x.equals(z)应该返回true 。
  • 一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,没有设置中使用的信息equals比较上的对象被修改。
  • 对于任何非空的参考值x , x.equals(null)应该返回false 。

toString()

返回对象的字符串表示形式,getClass()返回对象的类对象,getClassName()以String形式返回类对象的名称(含包名)。Integer.toHexString(hashCode())则是以对象的哈希码为实参,以16进制无符号整数形式返回此哈希码的字符串表示形式。

finalize()

一个子类覆盖了finalize方法,当垃圾回收此对象之前会调用此方法,但是只会调用一次,加入这次在finalize()方法中让此对象有引用指向他,那么下次再回收此对象时就不会调用此方法。

这篇关于吃透Java基础五:Class类和Object类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131685

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]