java安全详细解析

  

<强>问题
  

  

(1)不安全是什么?

  

(2)不安全只有中科院的功能吗?

  

(3)不安全为什么是不安全的吗?

  

(4)怎么使用安全吗?

  

<强>简介
  

  

不安全为我们提供了访问底层的机制,这种机制仅供java核心类库使用,而不应该被普通用户使用。

  

但是,为了更好地了解java的生态体系,我们应该去学习它,去了解它,不求深入到底层的C/c++代码,但求能了解它的基本功能。

  

<强>获取不安全的实例
  

  

查看不安全的源码我们会发现它提供了一个getUnsafe()的静态方法。

  <>之前   @CallerSensitive   公共静态安全getUnsafe () {   类var0=Reflection.getCallerClass ();   如果(! VM.isSystemDomainLoader (var0.getClassLoader ())) {   把新SecurityException(“不安全”);   其他}{   返回theUnsafe;   }   }   

但是,如果直接调用这个方法会抛出一个SecurityException异常,这是因为不安全仅供java内部类使用,外部类不应该使用它。

  

那么,我们就没有方法了吗?

  

当然不是,我们有反射啊!查看源码,我们发现它有一个属性叫theUnsafe,我们直接通过反射拿到它即可。

  <>之前   公开课UnsafeTest {   公共静态void main (String [] args)抛出NoSuchFieldException, IllegalAccessException {   场f=Unsafe.class.getDeclaredField (“theUnsafe”);   f.setAccessible(真正的);   不安全不安全=(不安全)f.get(空);   }   }   

<强>使用安全实例化一个类

  

假如我们有一个简单的类如下:

  <>之前   类用户{   int年龄;      公共用户(){   这一点。年龄=10;   }   }   

如果我们通过构造方法实例化这个类,时代属性将会返回10。

  <>之前   用户user1=新用户();//打印10   System.out.println (user1.age);   

如果我们调用不安全来实例化呢?

  <>之前   用户user2=(用户)unsafe.allocateInstance (User.class);//打印0   System.out.println (user2.age);   

年龄将返回0,因为Unsafe.allocateInstance()只会给对象分配内存,并不会调用构造方法,所以这里只会返回int类型的默认值0。

  

<>强修改私有字段的值

  

使用不安全的putXXX()方法,我们可以修改任意私有字段的值。

  <>之前   公开课UnsafeTest {   公共静态void main (String [] args)抛出NoSuchFieldException, IllegalAccessException InstantiationException {   场f=Unsafe.class.getDeclaredField (“theUnsafe”);   f.setAccessible(真正的);   不安全不安全=(不安全)f.get(空);      用户用户=新用户();   场年龄=user.getClass () .getDeclaredField(“年龄”);   不安全的。putInt(用户、unsafe.objectFieldOffset(年龄),20);//打印20   System.out.println (user.getAge ());   }   }      类用户{   私人int年龄;      公共用户(){   这一点。年龄=10;   }      公共int getAge () {   返回年龄;   }   }   

一旦我们通过反射调用得到字段的年龄,我们就可以使用安全将其值更改为任何其他int值。(当然,这里也可以通过反射直接修改)

  

<强>抛出检查异常

  

我们知道如果代码抛出了检查异常,要不就使用try…catch捕获它,要不就在方法签名上定义这个异常,但是,通过不安全我们可以抛出一个检查异常,同时却不用捕获或在方法签名上定义它。

  <>之前//使用正常方式抛出IOException需要定义在方法签名上往外抛   公共静态孔隙readFile()抛出IOException {   把新IOException ();   }//使用安全抛出异常不需要定义在方法签名上往外抛   公共静态孔隙readFileUnsafe () {   不安全的。throwException(新IOException ());   }   

<强>使用堆外内存

  

如果进程在运行过程中JVM上的内存不足了,会导致频繁的进行GC。理想情况下,我们可以考虑使用堆外内存,这是一块不受JVM管理的内存。

  

使用不安全的allocateMemory()我们可以直接在堆外分配内存,这可能非常有用,但我们要记住,这个内存不受JVM管理,因此我们要调用freeMemory()方法手动释放它。

  

假设我们要在堆外创建一个巨大的int数组,我们可以使用allocateMemory()方法来实现:

  <>之前   类OffHeapArray {//一个int等于4个字节   私有静态最终int int=4;   私人长尺寸;   私人长地址;      私有静态不安全不安全;   静态{   尝试{   场f=Unsafe.class.getDeclaredField (“theUnsafe”);   f.setAccessible(真正的);   不安全=(不安全)f.get(空);   }捕捉(NoSuchFieldException e) {   e.printStackTrace ();   }捕捉(IllegalAccessException e) {   e.printStackTrace ();   }   }//构造方法,分配内存   公共OffHeapArray(长尺寸){   这一点。大?大小;//参数字节数   地址=不安全。allocateMemory(大小* INT);   }//获取指定索引处的元素   公共int(我){   返回不安全。getInt(地址+ i * INT);   }//设置指定索引处的元素   公共空集(长我,int值){   不安全的。putInt(地址+ i * INT值);   }//元素个数   公共长尺寸(){   返回大小;   }//释放堆外内存   公共空间freeMemory () {   unsafe.freeMemory(地址);   }   }

java安全详细解析