臭名昭著的sun.misc.Unsafe解释

Java虚拟机的最大竞争对手可能是托管C#等语言的Microsoft CLR 。 CLR允许编写不安全的代码作为低级编程的入口,这在JVM上很难实现。 如果您需要Java中的此类高级功能,则可能会被迫使用JNI ,这需要您了解一些C并Swift导致代码紧密耦合到特定平台。 使用sun.misc.Unsafe ,尽管不鼓励使用Java API在Java plarform上进行低级编程,但还有另一种选择。 尽管如此,仍有一些应用程序依赖于sun.misc.Unsafe (例如objenesis)以及所有基于后者的库(例如kryo) ,例如kryo ,该库再次用于Twitter的Storm中 。 因此,现在该看看一下了,特别是因为sun.misc.Unsafe的功能被认为已成为Java 9中Java公共API的一部分 。

取得sun.misc.Unsafe实例

sun.misc.Unsafe类旨在仅由核心Java类使用,因此其作者将其唯一的构造函数设为私有,并且仅添加了一个同样私有的singleton实例。 此实例的公共获取程序将执行安全检查,以避免其公共使用:

public static Unsafe getUnsafe() {Class cc = sun.reflect.Reflection.getCallerClass(2);if (cc.getClassLoader() != null)throw new SecurityException("Unsafe");return theUnsafe;
}

此方法首先从当前线程的方法堆栈中查找调用的Class 。 该查找由另一个名为sun.reflection.Reflection内部类实现,该内部类基本上是浏览给定数量的调用堆栈帧,然后返回此方法的定义类。 但是,此安全检查可能会在将来的版本中更改 。 浏览堆栈时,第一个找到的类(索引0 )显然是Reflection类本身,第二个(索引1 )类将是Unsafe类,这样索引2将保存正在调用Unsafe#getUnsafe()

然后检查此查找的类的ClassLoader ,其中使用null引用表示HotSpot虚拟机上的引导程序类加载器。 (这在Class#getClassLoader()中有说明,其中说“ 某些实现可能使用null来表示引导类加载器 ”。)由于通常不会在该类加载器中加载非核心Java类,因此您永远不会能够直接调用此方法,但收到抛出的SecurityException作为答案。 (从技术上讲,您可以通过将引导程序类加载器添加到–Xbootclasspath来强制VM使用引导程序类加载器来加载应用程序类,但这需要在应用程序代码之外进行一些设置,您可能希望避免这种设置。)因此,进行以下测试将会成功:

@Test(expected = SecurityException.class)
public void testSingletonGetter() throws Exception {Unsafe.getUnsafe();
}

但是,安全检查的设计不当,应视为对单例反模式的警告。 只要不禁止使用反射 (这很困难,因为在许多框架中广泛使用反射 ),您总是可以通过检查类的私有成员来获得实例。 从Unsafe类的源代码中,您可以了解到单例实例存储在名为theUnsafe的私有静态字段中。 对于HotSpot虚拟机至少是这样。 对于我们来说不幸的是,其他虚拟机实现有时对此字段使用其他名称。 例如,Android的Unsafe类将其单例实例存储在名为THE_ONE的字段中。 这使得很难提供一种“兼容”的方式来接收实例。 但是,由于我们已经通过使用Unsafe类离开了兼容性的保存范围,因此我们不必为此担心,而应该比完全使用该类还要担心。 为了掌握单例实例,您只需读取单例字段的值即可:

Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);

或者,您可以调用私人教练。 我个人更喜欢这种方式,因为它可以与Android一起使用,而提取字段却不能:

Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor();
unsafeConstructor.setAccessible(true);
Unsafe unsafe = unsafeConstructor.newInstance();

您为这种次要的兼容性优势所付出的代价是最小的堆空间。 但是,在字段或构造函数上使用反射时执行的安全性检查类似。

创建类的实例而不调用构造函数

我第一次使用Unsafe类是为了创建类的实例而不调用任何类的构造函数。 我需要代理整个类,该类只具有一个嘈杂的构造函数,但我只想将所有方法调用委托给一个实际实例,但是在构造时我还不知道。 创建子类很容易,如果该类已由接口表示,则创建代理将是一件简单的事情。 但是,对于昂贵的构造函数,我陷入了困境。 通过使用Unsafe类,我得以解决该问题。 考虑一个带有虚假的构造函数的类:

class ClassWithExpensiveConstructor {private final int value;private ClassWithExpensiveConstructor() {value = doExpensiveLookup();}private int doExpensiveLookup() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return 1;}public int getValue() {return value;}
}

使用Unsafe ,我们可以创建ClassWithExpensiveConstructor (或其任何子类)的实例,而不必调用上述构造函数,只需直接在堆上分配实例即可:

@Test
public void testObjectCreation() throws Exception {ClassWithExpensiveConstructor instance = (ClassWithExpensiveConstructor)unsafe.allocateInstance(ClassWithExpensiveConstructor.class);assertEquals(0, instance.getValue());
}

请注意,final字段尚未由构造方法初始化,但使用其类型的默认值进行设置 。 除此之外,构造的实例的行为类似于普通的Java对象。 例如,当它变得不可访问时,将被垃圾回收。

Java运行时本身在创建对象(例如反序列化)时无需调用构造函数即可创建对象。 因此, ReflectionFactory提供了更多访问单个对象的权限:

@Test
public void testReflectionFactory() throws Exception {@SuppressWarnings("unchecked")Constructor<ClassWithExpensiveConstructor> silentConstructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(ClassWithExpensiveConstructor.class, Object.class.getConstructor());silentConstructor.setAccessible(true);assertEquals(10, silentConstructor.newInstance().getValue());
}

请注意, ReflectionFactory类只需要一个RuntimePermission呼吁reflectionFactoryAccess接收的单一实例,因此没有反映这里需要。 收到的ReflectionFactory实例允许您定义任何构造函数以成为给定类型的构造函数。 在上面的示例中,我为此使用了默认的java.lang.Object构造函数。 但是,您可以使用任何构造函数:

class OtherClass {private final int value;private final int unknownValue;private OtherClass() {System.out.println("test");this.value = 10;this.unknownValue = 20;}
}@Test
public void testStrangeReflectionFactory() throws Exception {@SuppressWarnings("unchecked")Constructor<ClassWithExpensiveConstructor> silentConstructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(ClassWithExpensiveConstructor.class,OtherClass.class.getDeclaredConstructor());silentConstructor.setAccessible(true);ClassWithExpensiveConstructor instance = silentConstructor.newInstance();assertEquals(10, instance.getValue());assertEquals(ClassWithExpensiveConstructor.class, instance.getClass());assertEquals(Object.class, instance.getClass().getSuperclass());
}

请注意,即使调用了完全不同的类的构造函数,也已在此构造函数中设置了value 。 然而,目标类中不存在的字段也会被忽略,从上面的示例中也可以明显看出。 请注意, OtherClass不会成为构造的实例类型层次结构的一部分,只需为“序列化”类型借用OtherClass的构造函数。

此博客条目中未提及的是其他方法,例如Unsafe#defineClassUnsafe#defineAnonymousClassUnsafe#ensureClassInitialized 。 但是,公共API的ClassLoader也定义了类似的功能。

本机内存分配

您是否曾经想过用Java分配一个数组,该数组应该具有多个Integer.MAX_VALUE条目? 可能不是因为这不是一项常见任务,但是如果您曾经需要此功能,则可以实现。 您可以通过分配本机内存来创建这样的数组。 本机内存分配例如由Java的NIO包中提供的直接字节缓冲区使用。 除了堆内存之外,本机内存不是堆区域的一部分,可以非排他性地用于例如与其他进程进行通信。 结果,Java的堆空间与本机空间竞争:分配给JVM的内存越多,剩余的本机内存就越少。

让我们看一个示例,该示例在Java中使用本地(堆外)内存创建上述超大数组:

class DirectIntArray {private final static long INT_SIZE_IN_BYTES = 4;private final long startIndex;public DirectIntArray(long size) {startIndex = unsafe.allocateMemory(size * INT_SIZE_IN_BYTES);unsafe.setMemory(startIndex, size * INT_SIZE_IN_BYTES, (byte) 0);}}public void setValue(long index, int value) {unsafe.putInt(index(index), value);}public int getValue(long index) {return unsafe.getInt(index(index));}private long index(long offset) {return startIndex + offset * INT_SIZE_IN_BYTES;}public void destroy() {unsafe.freeMemory(startIndex);}
}@Test
public void testDirectIntArray() throws Exception {long maximum = Integer.MAX_VALUE + 1L;DirectIntArray directIntArray = new DirectIntArray(maximum);directIntArray.setValue(0L, 10);directIntArray.setValue(maximum, 20);assertEquals(10, directIntArray.getValue(0L));assertEquals(20, directIntArray.getValue(maximum));directIntArray.destroy();
}

首先,请确保您的计算机有足够的内存来运行此示例! 您至少需要(2147483647 + 1) * 4 byte = 8192 MB本机内存才能运行代码。 如果您使用过其他编程语言(例如C),则每天都要进行直接内存分配。 通过调用Unsafe#allocateMemory(long) ,虚拟机将为您分配请求的本机内存量。 之后,您有责任正确处理此内存。

存储特定值所需的内存量取决于类型的大小。 在上面的示例中,我使用了一个int类型,该类型表示32位整数。 因此,单个int值消耗4个字节。 对于基本类型, 大小有据可查 。 但是,计算对象类型的大小更为复杂,因为它们取决于类型层次结构中任何地方声明的非静态字段的数量。 计算对象大小的最典型方法是使用Java的Attach API中的Instrumented类,该类为此目的提供了一种专用方法,称为getObjectSize 。 但是,在本节的最后,我将评估处理对象的另一种(hacky)方式。

请注意,直接分配的内存始终是本机内存 ,因此不会进行垃圾回收。 因此,如上例所示,您必须通过调用Unsafe#freeMemory(long)显式释放内存。 否则,您将保留一些内存,只要JVM实例正在运行,就无法将其用于其他用途,这是内存泄漏和非垃圾收集语言中的常见问题。 或者,您也可以通过调用Unsafe#reallocateMemory(long, long)直接在某个地址重新分配内存,其中第二个参数描述了JVM在给定地址保留的新字节数。

另外,请注意,直接分配的内存使用特定值初始化。 通常,您会从该内存区域的旧用法中发现垃圾,因此如果需要默认值,则必须显式初始化分配的内存。 当您让Java运行时为您分配内存时,通常会为您完成此操作。 在上面的示例中,借助于Unsafe#setMemory方法,整个区域被零覆盖。

使用直接分配的内存时,JVM都不会为您执行范围检查。 因此,如以下示例所示,可能会破坏您的内存:

@Test
public void testMallaciousAllocation() throws Exception {long address = unsafe.allocateMemory(2L * 4);unsafe.setMemory(address, 8L, (byte) 0);assertEquals(0, unsafe.getInt(address));assertEquals(0, unsafe.getInt(address + 4));unsafe.putInt(address + 1, 0xffffffff);assertEquals(0xffffff00, unsafe.getInt(address));assertEquals(0x000000ff, unsafe.getInt(address + 4));
}

请注意,我们在空间中写入了一个值,该值分别部分保留给第一个和第二个数字。 这张照片可能会清除一切。 请注意,内存中的值是从“右向左”运行的(但这可能取决于计算机)。

无标题

第一行显示将零写入整个分配的本机内存区域后的初始状态。 然后,我们使用32个字节覆盖4个字节,并以单个字节的偏移量覆盖。 最后一行显示此写入操作后的结果。

最后,我们想将整个对象写入本地内存。 如上所述,这是一项艰巨的任务,因为我们首先需要计算对象的大小才能知道我们需要保留的大小。 但是,Unsafe类不提供此类功能。 至少不是直接地,因为我们至少可以使用Unsafe类来查找实例字段的偏移量,JVM自身在堆上分配对象时会使用该实例字段的偏移量。 这使我们能够找到对象的近似大小:

public long sizeOf(Class<?> clazz)long maximumOffset = 0;do {for (Field f : clazz.getDeclaredFields()) {if (!Modifier.isStatic(f.getModifiers())) {maximumOffset = Math.max(maximumOffset, unsafe.objectFieldOffset(f));}}} while ((clazz = clazz.getSuperclass()) != null);return maximumOffset + 8;
}

乍一看,这似乎很神秘,但是此代码背后没有什么大秘密。 我们只是简单地遍历在类本身或其任何超类中声明的所有非静态字段。 我们不必担心接口,因为它们无法定义字段,因此永远不会更改对象的内存布局。 这些字段中的任何一个都有一个偏移量,该偏移量表示当JVM将此类实例存储在内存中时,该字段的值相对于用于该对象的第一个字节占用该字段的第一个字节。 我们只需找到最大偏移量即可找到除最后一个字段以外的所有字段所需的空间。 由于在64位计算机上运行时,字段对于long值或double值或对象引用的占用空间永远不会超过64位(8字节),因此我们至少找到了用于存储空间的上限。宾语。 因此,我们只需将这8个字节添加到最大索引中,就不会遇到保留很小空间的危险。 这个想法当然会浪费一些字节,并且应该在生产代码中使用更好的算法。

在这种情况下,最好将类定义视为异构数组的一种形式。 请注意,最小字段偏移量不是0而是正值。 前几个字节包含元信息。 下图通过一个int和一个long字段(其中两个字段都有偏移量)的示例对象形象化了该原理。 请注意,在将对象的副本写入本机内存时,我们通常不会写入元信息,因此我们可以进一步减少使用的本机便笺的数量。 还要注意,此内存布局可能高度依赖于Java虚拟机的实现。

object_layout

通过这种过度仔细的估计,我们现在可以实现一些存根方法,将对象的浅表副本直接写入本机内存。 请注意,本机内存并不真正了解对象的概念。 我们基本上只是将给定的字节数设置为反映对象当前值的值。 只要我们记住此类型的内存布局,这些字节就包含了足以重构此对象的信息。

public void place(Object o, long address) throws Exception {Class clazz = o.getClass();do {for (Field f : clazz.getDeclaredFields()) {if (!Modifier.isStatic(f.getModifiers())) {long offset = unsafe.objectFieldOffset(f);if (f.getType() == long.class) {unsafe.putLong(address + offset, unsafe.getLong(o, offset));} else if (f.getType() == int.class) {unsafe.putInt(address + offset, unsafe.getInt(o, offset));} else {throw new UnsupportedOperationException();}}}} while ((clazz = clazz.getSuperclass()) != null);
}public Object read(Class clazz, long address) throws Exception {Object instance = unsafe.allocateInstance(clazz);do {for (Field f : clazz.getDeclaredFields()) {if (!Modifier.isStatic(f.getModifiers())) {long offset = unsafe.objectFieldOffset(f);if (f.getType() == long.class) {unsafe.putLong(instance, offset, unsafe.getLong(address + offset));} else if (f.getType() == int.class) {unsafe.putLong(instance, offset, unsafe.getInt(address + offset));} else {throw new UnsupportedOperationException();}}}} while ((clazz = clazz.getSuperclass()) != null);return instance;
}@Test
public void testObjectAllocation() throws Exception {long containerSize = sizeOf(Container.class);long address = unsafe.allocateMemory(containerSize);Container c1 = new Container(10, 1000L);Container c2 = new Container(5, -10L);place(c1, address);place(c2, address + containerSize);Container newC1 = (Container) read(Container.class, address);Container newC2 = (Container) read(Container.class, address + containerSize);assertEquals(c1, newC1);assertEquals(c2, newC2);
}

请注意,这些用于在本机内存中写入和读取对象的存根方法仅支持intlong字段值。 当然, Unsafe支持所有原始值,甚至可以通过使用方法的易失性形式编写值,而无需访问线程本地缓存。 存根仅用于使示例简洁。 请注意,由于这些“实例”是直接分配其内存的,因此永远不会垃圾回收。 (但是,也许这就是您想要的。)此外,在计算大小时要小心,因为对象的内存布局可能取决于VM,并且与32位计算机相比,如果64位计算机运行您的代码,则该对象也会更改。 偏移甚至可能在JVM重新启动之间发生变化。

为了读取和编写原语或对象引用, Unsafe提供了以下类型相关的方法:

  • getXXX(Object target, long offset) :将在指定的偏移量处从目标地址读取XXX类型的值。
  • putXXX(Object target, long offset, XXX value) :将值放置在目标地址的指定偏移量处。
  • getXXXVolatile(Object target, long offset) :将在指定的偏移量处从目标地址读取XXX类型的值,并且不会命中任何线程本地缓存。
  • putXXXVolatile(Object target, long offset, XXX value) :将值放置在目标地址处的指定偏移量处,并且不会命中任何线程本地缓存。
  • putOrderedXXX(Object target, long offset, XXX value) :将值放置在指定offet的目标地址上,并且可能不会访问所有线程本地缓存。
  • putXXX(long address, XXX value) :将XXX类型的指定值直接放在指定地址。
  • getXXX(long address) :将从指定地址读取XXX类型的值。
  • compareAndSwapXXX(Object target, long offset, long expectedValue, long value) :将从目标地址的指定偏移量原子读取一个XXX类型的值,如果此偏移量的当前值等于预期值,则设置给定值。

请注意,使用getObject(Object, long)方法族在本地内存中写入或读取对象副本时,您正在复制引用。 因此,在应用上述方法时,您仅创建实例的浅表副本。 但是,您始终可以递归读取对象大小和偏移量并创建深层副本。 但是,请注意循环对象引用,当不小心应用此原理时,循环引用会导致无限循环。

这里没有提到Unsafe类中的现有实用程序,这些实用程序允许处理诸如staticFieldOffset类的静态字段值并用于处理数组类型。 最后,两种名为Unsafe#copyMemory方法Unsafe#copyMemory可以指示相对于特定对象偏移量或绝对地址的直接内存复制,如以下示例所示:

@Test
public void testCopy() throws Exception {long address = unsafe.allocateMemory(4L);unsafe.putInt(address, 100);long otherAddress = unsafe.allocateMemory(4L);unsafe.copyMemory(address, otherAddress, 4L);assertEquals(100, unsafe.getInt(otherAddress));
}

抛出未经检查的检查异常

Unsafe中还有其他有趣的方法可以找到。 您是否曾经想过要抛出特定的异常以在较低层中进行处理,但是您的高层接口类型并未声明此已检查异常? Unsafe#throwException允许这样做:

@Test(expected = Exception.class)
public void testThrowChecked() throws Exception {throwChecked();
}public void throwChecked() {unsafe.throwException(new Exception());
}

本机并发

使用parkunpark方法,您可以将线程暂停一定时间并恢复它:

@Test
public void testPark() throws Exception {final boolean[] run = new boolean[1];Thread thread = new Thread() {@Overridepublic void run() {unsafe.park(true, 100000L);run[0] = true;}};thread.start();unsafe.unpark(thread);thread.join(100L);assertTrue(run[0]);
}

此外,可以通过使用monitorEnter(Object)monitorExit(Object)tryMonitorEnter(Object)使用Unsafe直接获取监视器。

  • 包含此博客条目所有示例的文件的主旨是可用 。

参考: 臭名昭著的sun.misc.Unsafe在我的Java每日博客上由我们的JCG合作伙伴 Rafael Winterhalter 解释 。

翻译自: https://www.javacodegeeks.com/2013/12/the-infamous-sun-misc-unsafe-explained.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366114.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

主从复制

五 主从复制 Replication(重要&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;) 5.1、介绍 基于主库二进制日志实时恢复到备库。 5.2、原理 5.2.1 主从复制的前提 &#xff08;1&#xff09;两台或两台以上数据库实例 &#xff08;2&#xff09;主库…

python输出格式控制_Python3.x那些事儿:[50]多种多样的输出格式

目前有两种方式来格式化输出格式&#xff0c;第一种就是自己动手来进行字符串的操作&#xff0c;虽然麻烦&#xff0c;但是都能实现。第二种方式就是使用str.format()函数。 string模块包含了一个Template类&#xff0c;这个类提供了把值替换成字符串的方法。 python提供把任意…

暑假第十五测

题解&#xff1a; 第一题&#xff1a; 20%枚举长度和每个子串&#xff0c;O&#xff08;len&#xff09;判断&#xff0c;随机情况复杂度可过 40%同样枚举长度&#xff0c;然后两个指针卡出区间&#xff0c;O(1)[或O(26)//可能可过&#xff1f;]判断 50%既然知道了40%的做法那…

zabbix磁盘的自动发现与磁盘指标监控

由于最近项目上需要对服务器监控进行规范化监控&#xff0c;再磁盘这块有几种方式 1.如果每台设备的磁盘是一样的 比如都有vda,vdb两块磁盘那么可以采用 1.1 每台客户端写脚本&#xff0c;服务端每台设备去加上监控项&#xff08;------最次的手段-------------&#xff09; 1.…

php前台用户权限开通,vue实现网站前台的权限管理

本文主要介绍了基于vue实现网站前台的权限管理(前后端分离实践)&#xff0c;小编觉得挺不错的&#xff0c;现在分享给大家&#xff0c;也给大家做个参考。一起跟随小编过来看看吧&#xff0c;希望能帮助到大家。Javascript做为当下的热门语言&#xff0c;用途很广泛&#xff0c…

应用ForkJoin –从最佳到快速

到目前为止&#xff0c;JDK 7已很好地掌握在开发人员手中&#xff0c;并且大多数人都听说过ForkJoin&#xff0c;但是没有多少人有时间或机会去尝试它。 它引起了&#xff0c;并且可能仍然引起一些混乱&#xff0c;与普通线程池有什么不同。 [1] 我在本文中的目标是通过一个代…

Echarts-K线图提示框改头换面

工作&#xff1a; 使用Hbuilder建web工程&#xff0c;加入echarts相关库&#xff0c;根据需要更改K线图及其的提示样式&#xff0c;去除默认提示&#xff0c;使用异步加载echarts的数据&#xff0c;数据格式为json。 需要注意的K线图和5日均线&#xff0c;10日均线的意义&#…

vc6.0 matlab混合编程,matlab2010 + vc6.0混合编程实例(调用dll)

不想解释太多直接上代码吧&#xff01;&#xff01;&#xff01;在对matlab配置后&#xff0c;上代码mcc -W cpplib:libMyAdd -T link:lib MyAdd -C就可以了&#xff0c;记得加上-C在对VC6.0进行配置的时候只要把 matlabroot\extern\include和matlabroot\extern\lib\win32\micr…

canvas换图时候会闪烁_Canvas实现图片上标注、缩放、移动和保存历史状态,纯干货(附CSS 3变化公式)...

(给前端大学加星标&#xff0c;提升前端技能.)作者&#xff1a;zhcxk1998https://juejin.im/user/5d4304bdf265da03d15531dc哈哈哈俺又来啦&#xff0c;这次带来的是canvas实现一些画布功能的文章&#xff0c;希望大家喜欢&#xff01;这个css3变化公式可以适用于平常我们使用的…

RMI强制Full GC每小时运行一次

在我职业生涯中进行的所有故障排除练习中&#xff0c;我感到随着时间的推移&#xff0c;我所追寻的错误在不断发展&#xff0c;变得越来越卑鄙和丑陋。 也许仅仅是我的年龄开始了。这个特别的Heisenbug –看起来像这篇帖子一样&#xff0c;再次让我清醒了很多&#xff0c;而不是…

oracle 安装ora 27102,ORA-27102 解决办法

因为在32位操作系统上执行了如下的操作alter system set sga_max_size2G scopespfile;之后再重启数据库就会失败报出错误:ORA-27102Out of Memory解决的方法也很简单:新建一个文本文件 如initaaa.ora内容&#xff1a;SPFILE../product/10.2.0&#xff0f;db_1/dbs/spfileorcl.o…

Codechef August Challenge 2018 : Modular GCD

传送门 一开始还手动拓欧找规律&#xff0c;发现好像玩不了。 然后想了想&#xff0c;A-B这个数比较小&#xff0c;枚举它的因子判断合不合法就行了。 需要特判AB的情况。 #include<cstdio> #include<algorithm> #define ll long long #define ld long double usin…

c语言 指针_C语言——指针

学习阶段&#xff1a;高中信竞、大学编程。前置知识&#xff1a;二进制与十六进制&#xff0c;C语言基础&#xff0c;数组。指针初学可能比较难理解&#xff0c;我这篇文章尽量用通俗易懂的方式来讲解。1. 指针概述为什么有指针这个东西&#xff1f;因为指针很贴近计算机内部的…

BZOJ 2141 排队(分块+树状数组)

题意 第一行为一个正整数n&#xff0c;表示小朋友的数量&#xff1b;第二行包含n个由空格分隔的正整数h1,h2,…,hn&#xff0c;依次表示初始队列中小朋友的身高&#xff1b;第三行为一个正整数m&#xff0c;表示交换操作的次数&#xff1b;以下m行每行包含两个正整数ai和bi&…

vant input框禁止调用手机键盘_【案例分享】适应网银等密码键盘的解决方案

在各种技术不断进步的大趋势下&#xff0c;对业务造成了极大影响&#xff0c;从大数据到云计算&#xff0c;再到人工智能&#xff0c;众多企业都开始步入技术改革&#xff0c;从而实现企业的创新。但与此同时&#xff0c;更多技术的引用&#xff0c;意味着更多的业务系统上线&a…

启动oracle数据库工具,Oracle数据库常用工具

SQL*Plus:SQL*Plus 是Oracle 数据库的一个基本工具&#xff0c;它允许用户使用SQL 命令交互式的访问数据库&#xff0c;也允许用户使用SQL*Plus 命令格式化输出参数。 通过SQL*Plus &#xff0c;可以完成数据库的启动和停止、创建和运行查询、更新数据、格式化输出数据报表、运…

Java 获取linux根目录下的文件夹_Windows支持直接访问Linux子系统文件:你的下一台Linux何必是Linux...

2020年第一波薅当当网羊毛的机会&#xff0c;别错过&#xff01;晓查 发自 凹非寺 量子位 报道 | 公众号 QbitAI 微软&#xff0c;致力于做最好的Linux发行版。今天&#xff0c;安装Windows 10测试版本号19603的用户发现&#xff0c;系统里WSL (Windows中的Linux子系统…

HTML5效果:实现树叶飘落

实现如图所示的东西效果&#xff08;落叶下落&#xff09;&#xff1a; html代码&#xff1a; <!DOCTYPE html><html><head><title>HTML5树叶飘落动画</title><meta charset"utf-8"><meta name"viewport" content&…

oracle 创交表,创建交叉报表(oracle)_oracle

创建交叉报表create table t1(goodid number(10) not null,saledate date not null,salesum number(10));要求生成本年度每个月的产品销售状况表m1 m2 m3 ... m12g1g2...gn下面是生成报表的sqlSELECT goodid,SUM(decode(to_char(saledate,mm),01,salesum)) "01"…

cass方格网数据excel_讨论|CASS怎么计算回字型土方? 124

大家好,欢迎来到我的专栏。这是我原创的第124篇CASS应用技术干货文章。希望对你有所帮助&#xff0c;写文不易&#xff0c;请点赞哦!回字型土方工程&#xff0c;就是计算区域内部&#xff0c;有一个或多个不参加计算的区域&#xff0c;这种区域也就是常说的“扣岛”。常见的有基…