返回首页

Android 开发入门教程有哪些推荐?

133 2023-12-04 16:32 admin

一、Android 开发入门教程有哪些推荐?

反射的概念

  • 反射:Refelection,反射是Java的特征之一,允许运行中的Java程序获取自身信息,并可以操作类或者对象的内部属性
  • 通过反射,可以在运行时获得程序或者程序中的每一个类型的成员活成成员的信息
  • 程序中的对象一般都是在编译时就确定下来,Java反射机制可以动态地创建对象并且调用相关属性,这些对象的类型在编译时是未知的
  • 也就是说 ,可以通过反射机制直接创建对象,即使这个对象类型在编译时是未知的
  • Java反射提供下列功能:
  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法,可以通过反射调用 private 方法
  • 在运行时调用任意一个对象的方法

反射调用方法原理

  1. 首先Java通过字节码获取类的基本信息,其次通过Class#getMethod("myMethod")经过查找获取Method对象
  2. 接着通过Method#invoke调用方法, 此处包括Native版本和Java版本实现
  3. Native版本的invoke0()在HotSpot VM里是由JVM_InvokeMethod()支持
  4. JVM_InvokeMethod()中通过JNIHandles::resolve(method)解析方法的符号引用(个人理解, 详情参考R大博客)
  5. 拿到method_handle后, 即符号引用, 获取方法的返回类型等相关信息, 最后调用invoke()执行方法(个人理解, 详情参考R大博客)
  6. 含native版本以及Java版本, native版本初始化快, 但由于对JVM是黑盒, 因此无法内联等优化, 当超过15次时, 会自动转成Java版本, Java版本初始化慢, 但长时间执行效率更高, 可进行内联等优化
public final  
  class Method extends AccessibleObject implements GenericDeclaration, Member {
    public Object invoke(Object obj, Object... args)  
           throws IllegalAccessException, IllegalArgumentException,  
           InvocationTargetException  
   {  
       ...
       return methodAccessor.invoke(obj, args);  
   }  

  }

// methodAccessor通过ReflectionFactory实例化返回
public class ReflectionFactory {
  public MethodAccessor newMethodAccessor(Method method) {  
        ...

        if (noInflation) {  
            return new MethodAccessorGenerator().  
                generateMethod(method.getDeclaringClass(),  
                               method.getName(),  
                               method.getParameterTypes(),  
                               method.getReturnType(),  
                               method.getExceptionTypes(),  
                               method.getModifiers());  
        } else {  
            NativeMethodAccessorImpl acc =  
                new NativeMethodAccessorImpl(method);  
            DelegatingMethodAccessorImpl res =  
                new DelegatingMethodAccessorImpl(acc);  
            acc.setParent(res);  
            return res;  
        }  
    }  
}

// native版本则是直接调用Reflection::invoke_method()
class NativeMethodAccessorImpl extends MethodAccessorImpl {  

    ...
    public Object invoke(Object obj, Object[] args)  
        throws IllegalArgumentException, InvocationTargetException  
    {  
        if (++numInvocations > ReflectionFactory.inflationThreshold()) {  
            MethodAccessorImpl acc = (MethodAccessorImpl)  
                new MethodAccessorGenerator().  
                    generateMethod(method.getDeclaringClass(),  
                                   method.getName(),  
                                   method.getParameterTypes(),  
                                   method.getReturnType(),  
                                   method.getExceptionTypes(),  
                                   method.getModifiers());  
            parent.setDelegate(acc);  
        }  
     
        return invoke0(method, obj, args);  
    }  
     
    ...
     
    private static native Object invoke0(Method m, Object obj, Object[] args);  
}  

// Java版本, 通过MethodAccessorGenerator生成MethodAccessor的实现类
public class GeneratedMethodAccessor1 extends MethodAccessorImpl {      
    ...

    public Object invoke(Object obj, Object[] args)     
        throws IllegalArgumentException, InvocationTargetException {  
        ...
        try {  
            target.foo(arg0);  
        } catch (Throwable t) {  
            throw new InvocationTargetException(t);  
        }  
    }  
}

Field

使用反射获取或者修改一个变量的值时,编译器不会进行自动装/拆箱

public class FieldTrouble extends BaseTestClass {
  public Integer value;

  public static void main(String[] args) {
      FieldTrouble fieldTrouble = new FieldTrouble();
      Class<? extends FieldTrouble> cls = fieldTrouble.getClass();
      ...
      Field value = cls.getField("value");
      // 抛java.lang.IllegalArgumentException
      value.setInt(fieldTrouble, 23);
      ...
  }
}

访问限制阻止我们修改 final 类型的变量, final变量通过反射修改需要调用Filed#setAccessible(true) 在使用反射修改某个对象的成员变量前你要明白,这样做会造成一定程度的性能开销,因为在反射时这样的操作需要引发许多额外操作,比如验证访问权限等。另外使用反射也会导致一些运行时的计算优化失效

Method

synthetic method合成方法

public class Foo {

  private int get(){
    return 1;
  }
  private class Bar {
    private Bar() {
      System.out.println(get());
    }
  }
}

...
// Synthetic (合成)方法是由编译器产生的、源代码中没有的方法。当内部类与外部类之前有互相访问 private 属性、方法时,编译器会在运行时为调用方创建一个 synthetic 方法。
static int access$000(Foo); //多出来的 synthetic 方法,为了在 Bar 中的这段代码 System.out.println(get());

varagrs方法

public void testVarargs(String... args) {
    ...
  }
bride桥接方法, 为了兼容JDK 1.5版本以前的代码

反射慢的原因

  • 运行时通过Class对象查找Method等对象
  • 方法调用时, 编译器无法进行方法内联等优化
  • 需要校验, 根据方法名和签名查找方法的符号引用等

反射优化

  • 缓存, 避免多次加载
  • 调用method#setAccessible(true)避免安全检查缓存
  • 直接调用方法

反射的主要用途

  • 反射最重要的用途就是开发各种通用框架
  • 很多框架都是配置化的,通过 XML 文件配置 Bean
  • 为了保证框架的通用性,需要根据配置文件加载不同的对象或者类,调用不同的方法
  • 要运用反射,运行时动态加载需要加载的对象
  • 示例:
  • 在运用 Struts 2 框架的开发中会在 struts.xml 中配置 Action:
<action name="login"
               class="org.ScZyhSoft.test.action.SimpleLoginAction"
               method="execute">
           <result>/shop/shop-index.jsp</result>
           <result name="error">login.jsp</result>
       </action>
123456
  • 配置文件与 Action 建立映射关系
  • View 层发出请求时,请求会被 StrutsPrepareAndExecuteFilter 拦截
  • StrutsPrepareAndExecuteFilter会动态地创建Action实例
  • 请求 login.action
  • StrutsPrepareAndExecuteFilter 会解析 struts.xml 文件
  • 检索 actionnameloginAction
  • 根据 class 属性创建 SimpleLoginAction 实例
  • 使用 invoke 方法调用 execute 方法
  • 反射是各种容器实现的核心

反射的运用

  • 反射相关的类在 StrutsPrepareAndExecuteFilter
  • 反射可以用于:
  • 判断对象所属的类
  • 获得class对象
  • 构造任意一个对象
  • 调用一个对象
  • 九大预定义的Class对象:
  • 基本的Java类型: boolean, byte, char, short, int, long, float, double
  • 关键字void通过class属性的也表示为Class对象
  • 包装类或者void类的静态TYPE字段:
  • Integer.TYPE == int.class
  • Integer.class == int.class
  • 数组类型的Class实例对象:
  • Class<String[]> clz = String[].class;
  • 数组的Class对象如何比较是否相等:
  • 数组的维数
  • 数组的类型
  • Class类中的 isArray() ,用来判断是否表示一个数组类型

invoke方法

  • 在Java中很多方法都会调用 invoke 方法,很多异常的抛出多会定位到 invoke 方法:
java.lang.NullPointerException
  at ......
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:497)
123456

invoke执行过程

  • invoke 方法用来在运行时动态地调用某个实例的方法,实现如下:
@CallSensitive
public Object invoke(Object obj, Object ... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Refelection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    MethodAccessor ma = methodAccessor;
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}
1234567891011121314

权限检查

  • AccessibleObject类是Field,Method和Constructor对象的基类:
  • 提供将反射的对象标记为在使用时取消默认Java语言访问控制检查的能力
  • invoke方法会首先检查AccessibleObject的override属性的值:
  • override默认值为false:
  • 表示需要权限调用规则,调用方法时需要检查权限
  • 也可以使用 setAccessible() 设置为 true
  • override如果值为true:
  • 表示忽略权限规则,调用方法时无需检查权限
  • 也就是说,可以调用任意private方法,违反了封装
  • 如果override属性为默认值false,则进行进一步的权限检查:
  1. 首先用 Reflection.quickCheckMemberAccess(clazz, modifiers) 方法检查方法是否为 public 1.1 如果是public方法的话,就跳过本步 1.2 如果不是public方法的话,就用Reflection.getCallerClass()方法获取调用这个方法的Class对象,这是一个 native 方法
@CallerSensitive
    public static native Class<?> getCallerClass();

----------------------------------------------------------


- 在OpenJDK中可以找到getCallerClass方法的JNI入口-Reflection.c

JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__
(JNIEnv *env, jclass unused)
{
    return JVM_GetCallerClass(env, JVM_CALLER_DEPTH);
}

----------------------------------------------------------

- JVM_GetCallerClass的源码位于jvm.cpp中

VM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env, int depth))
  JVMWrapper("JVM_GetCallerClass");
  // Pre-JDK 8 and early builds of JDK 8 don't have a CallerSensitive annotation; or
  // sun.reflect.Reflection.getCallerClass with a depth parameter is provided
  // temporarily for existing code to use until a replacement API is defined.
  if (SystemDictionary::reflect_CallerSensitive_klass() == NULL || depth != JVM_CALLER_DEPTH) {
    Klass* k = thread->security_get_caller_class(depth);
    return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, k->java_mirror());
  }
  // Getting the class of the caller frame.
  //
  // The call stack at this point looks something like this:
  //
  // [0] [ @CallerSensitive public sun.reflect.Reflection.getCallerClass ]
  // [1] [ @CallerSensitive API.method                                   ]
  // [.] [ (skipped intermediate frames)                                 ]
  // [n] [ caller                                                        ]
  vframeStream vfst(thread);
  // Cf. LibraryCallKit::inline_native_Reflection_getCallerClass
  for (int n = 0; !vfst.at_end(); vfst.security_next(), n++) {
    Method* m = vfst.method();
    assert(m != NULL, "sanity");
    switch (n) {
    case 0:
      // This must only be called from Reflection.getCallerClass
      if (m->intrinsic_id() != vmIntrinsics::_getCallerClass) {
        THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVM_GetCallerClass must only be called from Reflection.getCallerClass");
      }
      // fall-through
    case 1:
      // Frame 0 and 1 must be caller sensitive.
      if (!m->caller_sensitive()) {
        THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), err_msg("CallerSensitive annotation expected at frame %d", n));
      }
      break;
    default:
      if (!m->is_ignored_by_security_stack_walk()) {
        // We have reached the desired frame; return the holder class.
        return (jclass) JNIHandles::make_local(env, m->method_holder()->java_mirror());
      }
      break;
    }
  }
  return NULL;
JVM_END
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. 获取 Class 对象 caller 后使用 checkAccess 方法进行一次快速的权限校验 ,checkAccess 方法实现如下:
volatile Object securityCheckCache;

    void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers) throws IllegalAccessException {
        if(caller == clazz){    // 快速校验
            return;             // 权限通过校验
        }
        Object cache = securityCheckCache;  // 读取volatile
        Class<?> targetClass = clazz;
        if (obj != null && Modifier.isProtected(modifiers) && ((targetClass = obj.getClass()) != clazz)) {  // 必须匹配caller,targetClass中的一个
            if (cache instanceof Class[]) {
                Class<?>[] cache2 = (Class<?>[]) cache;
                if (cache2[1] == targetClass && cache[0] == caller) {
                    return;     // 校验通过
                }
            }
        } else if (cache == caller) {
            return;             // 校验通过
        }
        slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
    }
1234567891011121314151617181920

首先先执行一次快速校验,一旦 Class 正确则权限检查通过;如果未通过,则创建一个缓存,中间再进行检查

  • 如果上面所有的权限检查都未通过,将会执行更详细的检查:
void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers, Class<?> targetClass) throws IllegalAccessException {
    Refelection.ensureMemberAccess(caller, clazz, obj, modifiers);
    // 如果成功,就更新缓存
    Object cache = ((targetClass == clazz) ? caller : new Class<?>[] {caller, targetClass});
    securityCheckCache = cache;
}
123456

Reflection.ensureMemberAccess 方法继续检查权限.若检查通过就更新缓存,这样下一次同一个类调用同一个方法时就不用执行权限检查了,这是一种简单的缓存机制

由于 JMMhappens-before 规则能够保证缓存初始化能够在写缓存之间发生,因此两个cache不需要声明为volatile

  • 检查权限的工作到此结束.如果没有通过检查就会抛出异常,如果通过检查就会到下一步

调用MethodAccessor的invoke方法

  • Method.invoke() 不是自身实现反射调用逻辑,而是通过 sun.refelect.MethodAccessor 来处理
  • Method对象的基本构成:
  • 每个 Java 方法有且只有一个 Method 对象作为 root, 相当于根对象,对用户不可见
  • 当创建 Method 对象时,代码中获得的 Method 对象相当于其副本或者引用
  • root 对象持有一个 MethodAccessor 对象,所有获取到的 Method 对象都共享这一个 MethodAccessor 对象
  • 必须保证 MethodAccessor 在内存中的可见性
  • root对象及其声明:
private volatile MethodAccessor methodAccessor;
/**
 * For sharing of MethodAccessors. This branching structure is
 * currently only two levels deep (i.e., one root Method and
 * potentially many Method objects pointing to it.)
 * 
 * If this branching structure would ever contain cycles, deadlocks can
 * occur in annotation code.
 */
private Method  root;
12345678910
  • MethodAccessor:
/**
 * This interface provides the declaration for
 * java.lang.reflect.Method.invoke(). Each Method object is
 * configured with a (possibly dynamically-generated) class which
 * implements this interface
 */
 public interface MethodAccessor {
    // Matches specification in {@link java.lang.reflect.Method}
    public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException;
 }
12345678910

MethodAccessor是一个接口,定义了 invoke() 方法,通过 Usage 可以看出 MethodAccessor 的具体实现类:

  1. sun.reflect.DelegatingMethodAccessorImpl
  2. sun.reflect.MethodAccessorImpl
  3. sun.reflect.NativeMethodAccessorImpl
  • 第一次调用 Java 方法对应的 Method 对象的 invoke() 方法之前,实现调用逻辑的 MethodAccess 对象还没有创建
  • 第一次调用时,才开始创建 MethodAccessor 并更新为 root, 然后调用 MethodAccessor.invoke() 完成反射调用
/**
 * NOTE that there is no synchronization used here. 
 * It is correct(though not efficient) to generate more than one MethodAccessor for a given Method.
 * However, avoiding synchronization will probably make the implementation more scalable.
 */

private MethodAccessor acquireMethodAccessor() {
    // First check to see if one has been created yet, and take it if so
    MethodAccessor tmp = null;
    if (root != null)
        tmp = root.getMethodAccessor();
    if (tmp != null) {
        methodAccessor = tmp;
    } else {
        tmp = reflectionFactory.newMethodAccessor(this);
        setMethodAccessor(tmp);
    } 
    return tmp;
}
12345678910111213141516171819
  • methodAccessor 实例由 reflectionFactory 对象操控生成 ,reflectionFactory 是在 AccessibleObject 中声明的:
/**
 * Reflection factory used by subclasses for creating field,
 * method, and constructor accessors. Note that this is called very early in the bootstrapping process.
 */
static final ReflectionFactory reflectionFactory = AccessController.doPrivileged(
                                                    new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
123456
  • sun.reflect.ReflectionFactory 方法:
public class ReflectionFactory {
    private static boolean initted = false;
    private static Permission reflectionFactoryAccessPerm = new RuntimePermission("reflectionFactoryAccess");
    private static ReflectionFactory soleInstance = new ReflectionFactory();
    // Provides access to package-private mechanisms in java.lang.reflect
    private static volatile LangReflectAccess langReflectAccess;

    /**
     * "Inflation" mechanism. Loading bytecodes to implement Method.invoke() and Constructor.
     * newInstance() currently costs 3-4x more than an invocation via native code for the first invocation (though subsequent invocations have been benchmarked to be over 20x faster)
     * Unfortunately this cost increases startup time for certain applications that use reflection intensively (but only once per class) to bootstrap themselves
     * To avoid this penalty we reuse the existing JVM entry points for the first few invocations of Methods and Constructors and then switch to the bytecode-based implementations
     */

    // Package-private to be accessible to NativeMethodAccessorImpl and NativeConstructorAccessorImpl
    private static noInflation = false;
    private static int inflationThreshold = 15;

    // 生成MethodAccessor
    public MethodAccessor newMethodAccessor(Method method) {
        checkInitted();

        if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
            return new MethodAccessorGenerator().generateMethod(method.getDeclaringClass(),
                                         method.getName(),
                                         method.getParameterTypes(),
                                         method.getReturnType(),
                                         method.getExceptionTypes(),
                                         method.getModifiers());
        } else {
            NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method);
            DelegatingMethodAccessorImpl res = new DelegatingMethodAccessorImpl(acc);
            acc.setParent(res);
            return res;
        }
    }

    /**
     * We have to defer full initialization of this class until after the static initializer is run since java.lang.reflect
     * Method's static initializer (more properly, that for java.lang.reflect.AccessibleObject) causes this class's to be run, before the system properties are set up
     */
     private static void checkInitted() {
        if (initted) return;
        AccessController.doPrivileged(
            new PrivilegedAction<Void>() {
                public Void run() {
                /**
                 * Tests to ensure the system properties table is fully initialized
                 * This is needed because reflection code is called very early in the initialization process (before command-line arguments have been parsed and therefore these user-settable properties installed
                 * We assume that if System.out is non-null then the System class has been fully initialized and that the bulk of the startup code has been run
                 */
                 if (System.out == null) {
                        // java.lang.System not yet fully initialized
                        return null;
                    }
                    String val = System.getProperty("sun.reflect.noInflation");
                    if (val != null && val.equals("true")) {
                        noInflation = true;
                    }
                    val = System.getProperty("sun.reflect.inflationThreshold");
                    if (val != null) {
                        try {
                            inflationThreshold = Integer.parseInt(val);
                        } catch (NumberFormatException e) {
                            throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e);
                        }
                    }
                    initted = true;
                    return null;
                }
            });
    }
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  • 实际的MethodAccessor实现有两个版本,一个是Java版本,一个是native版本,两者各有特点:
  • 初次启动时 Method.invoke()Constructor.newInstance() 方法采用native方法要比Java方法快3-4倍
  • 启动后 native 方法又要消耗额外的性能而慢于 Java 方法
  • Java实现的版本在初始化时需要较多时间,但长久来说性能较好
  • 这是HotSpot的优化方式带来的性能特性:
  • 跨越native边界会对优化有阻碍作用
  • 为了尽可能地减少性能损耗,HotSpot JDK采用inflation方式:
  • Java方法在被反射调用时,开头若干次使用native版
  • 等反射调用次数超过阈值时则生成一个专用的 MethodAccessor 实现类,生成其中的 invoke() 方法的字节码
  • 以后对该Java方法的反射调用就会使用Java版本
  • ReflectionFactory.newMethodAccessor()生成MethodAccessor对象的逻辑:
  • native 版开始会会生成 NativeMethodAccessorImplDelegatingMethodAccessorImpl 两个对象
  • DelegatingMethodAccessorImpl:
/* Delegates its invocation to another MethodAccessorImpl and can change its delegate at run time */
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
    private MethodAccessorImpl delegate;
    DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
        setDelegate(delegate);
    }
    public Object invoke(Object obj, Object[] args)
        throws IllegalArgumentException, InvocationTargetException
    {
        return delegate.invoke(obj, args);
    }
    void setDelegate(MethodAccessorImpl delegate) {
        this.delegate = delegate;
    }
}
123456789101112131415

DelegatingMethodAccessorImpl对象是一个中间层,方便在 native 版与 Java 版的 MethodAccessor 之间进行切换

  • native版MethodAccessor的Java方面的声明: sun.reflect.NativeMethodAccessorImpl
/* Used only for the first few invocations of a Method; afterward,switches to bytecode-based implementation */
class NativeMethodAccessorImpl extends MethodAccessorImpl {
    private Method method;
    private DelegatingMethodAccessorImpl parent;
    private int numInvocations;
    NativeMethodAccessorImpl(Method method) {
        this.method = method;
    }
    public Object invoke(Object obj, Object[] args)
        throws IllegalArgumentException, InvocationTargetException
    {
        /* We can't inflate methods belonging to vm-anonymous classes because that kind of class can't be referred to by name, hence can't be found from the generated bytecode */
        if (++numInvocations > ReflectionFactory.inflationThreshold()
                && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
            MethodAccessorImpl acc = (MethodAccessorImpl)
                new MethodAccessorGenerator().
                    generateMethod(method.getDeclaringClass(),
                                   method.getName(),
                                   method.getParameterTypes(),
                                   method.getReturnType(),
                                   method.getExceptionTypes(),
                                   method.getModifiers());
            parent.setDelegate(acc);
        }
        return invoke0(method, obj, args);
    }
    void setParent(DelegatingMethodAccessorImpl parent) {
        this.parent = parent;
    }
    private static native Object invoke0(Method m, Object obj, Object[] args);
}
12345678910111213141516171819202122232425262728293031
  • 每次 NativeMethodAccessorImpl.invoke() 方法被调用时,程序调用计数器都会增加 1, 看看是否超过阈值
  • 如果超过则调用 MethodAccessorGenerator.generateMethod() 来生成 Java 版的 MethodAccessor 的实现类
  • 改变 DelegatingMethodAccessorImpl 所引用的 MethodAccessorJava
  • 经由 DelegatingMethodAccessorImpl.invoke() 调用到的就是 Java 版的实现

invoke总结

以上就是Android开发中的invoke原理反射与原理;更多Android开发可以前往《Android核心技术手册》查看获取海量学习资料;里面内容包含Android开发中进阶技术30几个技术板块。

Android核心技术进阶手册、实战笔记、面试题纲资料
  • invoke方法的过程:
  • MagicAccessorImpl:
  • 原本Java的安全机制使得不同类之间不是任意信息都可见,但JDK里面专门设了个 MagicAccessorImpl 标记类开了个后门来允许不同类之间信息可以互相访问,由JVM管理
/** <P> MagicAccessorImpl (named for parity with FieldAccessorImpl and
    others, not because it actually implements an interface) is a
    marker class in the hierarchy. All subclasses of this class are
    "magically" granted access by the VM to otherwise inaccessible
    fields and methods of other classes. It is used to hold the code
    for dynamically-generated FieldAccessorImpl and MethodAccessorImpl
    subclasses. (Use of the word "unsafe" was avoided in this class's
    name to avoid confusion with {@link sun.misc.Unsafe}.) </P>
    <P> The bug fix for 4486457 also necessitated disabling
    verification for this class and all subclasses, as opposed to just
    SerializationConstructorAccessorImpl and subclasses, to avoid
    having to indicate to the VM which of these dynamically-generated
    stub classes were known to be able to pass the verifier. </P>
    <P> Do not change the name of this class without also changing the
    VM's code. </P> */
class MagicAccessorImpl {
}
1234567891011121314151617
  • @CallerSensitive注解
Summary: Improve the security of the JDK’s method-handle implementation by replacing the existing
 hand-maintained list of caller-sensitive methods with a mechanism that accurately identifies
  such methods and allows their callers to be discovered reliably.
/**
 * A method annotated @CallerSensitive is sensitive to its calling class,
 * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass},
 * or via some equivalent.
 *
 * @author John R. Rose
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({METHOD})
public @interface CallerSensitive {
}
1234567891011121314
  • 用@CallerSensitive注解修饰的方法从一开始就知道具体调用此方法的对象
  • 不用再经过一系列的检查就能确定具体调用此方法的对象
  • 实际上是调用 sun.reflect.Reflection.getCallerClass 方法
  • Reflection类位于调用栈中的0帧位置
  • sun.reflect.Reflection.getCallerClass() 方法返回调用栈中从0帧开始的第x帧中的类实例
  • 该方法提供的机制可用于确定调用者类,从而实现"感知调用者(Caller Sensitive)"的行为
  • 即允许应用程序根据调用类或调用栈中的其它类来改变其自身的行为

反射注意点

  • 反射会额外消耗系统资源,如果不需要动态地创建一个对象,就不要使用反射
  • 反射调用方法时可以忽略权限检查.可能会破坏封装性而导致安全问题

二、哪些 iOS 开发入门教程比较好?

我这里有一些教程,直接给你网址好了,应该还是挺不错的

【IOS课程|IOS视频课程】_e良师益友网

三、游戏设计与开发专业的发展路线?

答,游戏开发团队的核心职务,是开发团队的主策划、主美术和主程序。

看自己是偏重于内容策划?美术设计?还是偏重于编程,来确定自己的发展路线。

四、安卓开发入门教程?

1,首先要立项,然后寻找技术组团,策划游戏玩法,数据,场景。美术根据策划的要求制作图片,音乐,特效,模型之类的资源,程序根据策划的要求和美术的要求编写代码,实现功能。当大部分功能都实现,测试人员测试游戏,寻找bug,修改bug。当游戏修改到稳定状态就可以宣传了。

2,安卓(Android)游戏以及手机游戏开发的详细流程

首先说游戏设计部门

通常这是如下职位:游戏设计主负责(也有称主策划) 执行游戏设计师(称执行策划):分剧情策划,数据策划,也有不分的,大家一起提高。 辅助员(称辅助策划):做一些比较简单的表据维护,资料收集。

工作职责:

游戏设计主负责人:主要负责游戏设计的整体把握、给大家安排工作,审核工作,提高部门人员士气。,

剧情策划一般负责背景,任务等等故事性比较强的,要求文笔要好

数据策划再细分,为规则和数据平衡,包括规则的描述,公式确定,数据表设定等等。 辅助员,主要是收集资料,维护表格等等,比较不涉及核心的工作。 *注:有一些公司或者团队,在策划岗位,还有新的岗位,如:

表现策划:主要负责特效、动作、音效收集并提需求,部分如音效部分亦有策划来完成。 资源策划:主要负责UI设计,模型相关配置,资源管理等等。

下面是程序部门

主程序与主设计师,是对游戏引擎最了解的人,以主程序为最强。主程的主要工作,安排程序部门工作,定游戏的数据结构,定一些主要方案的完成方法。

一般程序员,分服务器端与客户端、服务器端程序,对于数据库结构,数据传输、通讯方式等等。客户端程序,对图像及优化有研究的会易受重用。

美术部门

主美负责整体美术风格的把握

原画绘制原画交于3D

2D负责贴图,游戏界面等的制作

3D负责3D建模,动作等方面工作

脚本与编辑器

在具体游戏实现时,越来越多的公司不会说把游戏中的数据写在C++里,而是用“脚本与数据库”的方式。

C++的作用是用来解释脚本和调用数据库的 在脚本中,写上, if { player hp >=30%hpmax add hp=hpmax }

这里的东西是写在脚本里的,C++就会解释,player、hp、hpmax是什么,hp、hpmax对应数据库是什么列主要的游戏内核是写在C里的,脚本用来实现游戏具体的一些东西。 如每个场景、每个NPC、每个道具都有可能有个脚本文件制定命令及数据一般由主程与主设计师一起来做,具体写脚本,一般为游戏设计部门按规范做这个工作。

编辑器:是高于脚本的

五、手机app开发入门教程?

手机app的开发主要分为7步:

1、确定软件开发的主要需求;

2、确定需求文档,并进行可行性评估

3、提交给APP开发团队;

4、功能需求确定,然后开始APP软件的原型策划以及UI界面策划;

5、原型图及UI界面策划完毕,开始程序开发;

6、程序开发完成,测试;

7、测试完成,然后提交

六、游戏设计和游戏开发哪个比较有意义?

游戏的设计和开发这东西本来就是一个扯淡的说法。设计是把一种计划、规划、设想通过视觉的形式传达出来的活动过程。开发是指在进行商业性生产或使用前,将研究成果或其他知识应用于某项计划或设计,以生产出新的或具有实质性改进的材料、装置、产品等。

从以上的定义严格来说,在游戏方面没有设计和开发一说,这样说的只是业外人士的称谓。在业内一般说是策划游戏和制作游戏……所以你可以直接说你们老师的命题太不入行直接拍死他。能设计的是游戏中的角色、游戏的玩法等内容,这些都是不同的工作内容,属于不同岗位的工作,不能混为一谈,……能开发的是游戏引擎,不是游戏……

游戏的研发,我们一般分成策划、程序、美术三个部分,策划负责游戏的构思、创意、玩法、玩点、特色等内容,研发则负责将策划的想法实现,美术则让游戏更加美观。可以说,策划所做的是搭建游戏的骨架,研发所做的是为这个骨架添置肌肉和神经,美术则是为游戏添加皮肤和塑造外形。

每一个岗位都是有关联的,如果非要比较意义的话…我们就假设一个策划,一个程序,一个美术,都是很强悍的存在,他们都很专注于本职工作,不会主动寻找事情,也没有其他的想法插足到其他人的工作之中。如果把他们放在一起制作游戏,没有策划开头,程序和美术将无所事事;没有程序,策划的想法不能实现,美术也不能看到自己的成果在游戏中的表现;没有美术…呃…你觉得恐龙和美女你喜欢看哪个?虽然美女没什么能力仅仅是花瓶而已……比较薪资那没什么太大的意义,因为国内的市场和国外不同……

暂时就说这么多吧……

七、花园设计入门教程?

如果你的房子拥有一片空地,那么恭喜你,

你已经成功拥有了无数人梦寐以求的花园庭院了。

庭院作为家的一部分,

园中的一花一草一物,

都应该以美好的姿态存在~

今天就来聊聊花园的设计技巧,

让你也能拥有一方美好的花园天地。

01 院子的隐私问题

如果院子空间有限,而又和邻居靠在一起,

就要考虑院子的私密性了。

可以利用高大的树木、灌木,或制作灌木篱笆,

或者建木栅栏或者直接砌一堵墙来遮挡。

02 庭院照明的设计

庭院里的照明有很多功能——提供照明作用,

确保有足够的亮度;

再一个是氛围灯,在夜晚会带来不一样的浪漫。

03 空间过渡

铺设或砖砌的露台空间,

可以营造视觉上开阔的庭院景观。

一个好的解决方案

就是使用逐步过渡的材料来铺设,

造成空间之间的连接效果。

04 软化边缘

利用网格状物来建立天井周边的一个温和边界,

这是一个非常不错的方法。

如果想为花的成长提供足够大的生长空间,

那要选择一个适合的地方,

例如在阳光充足的条件下种植三角梅。

待三角梅开花之时,丰富的颜色十分壮观,

这也许是个不错的选择。

05 混合材料装饰

不同的颜色或材料的一些小变化,

都能给人不同的视觉感受。

考虑这个因素,想在庭院搭建一个边界,

可以使用不同大小的石头来装扮座位,

例如在用餐区铺设红砖,

这有助于营造温暖的餐厅氛围。

06 利用硬体材料

用石头铺设地板,

可以让你的庭院缓和、不突兀地

过渡到庭院周围的石径。

壁炉附近的的矮墙

为客人坐供应了一个即兴的现场座位了。

07 庭院软装

软装不仅仅是户外家具,

各种装饰品,还有植物,

如果不想在你花园筑起一道墙,

你可以种植一些树来软化庭院的边境。

08 固定在前院的景观

对于庭院花园来说,前院是一个很特别的地方,

但为什么不好好利用这些优势呢?

用一些设计技巧,

可以为你创造一个具有小小空间的私人地方。

使用中等高度的集装箱来建立边界,

甚至一个种植草坪的丛地。

09 装饰艺术

每家庭院都有装饰元素,

如果你的风格有点不拘一格,

或有利于一个主题,

例如像森林这样的主题,

那么让装修方案反映这种风格,

并用雕塑装饰它。

10 打造庭院目的的多样性

要考虑如何让你的家具能够最大限度的利用到。

在这里,一张具有吧台高度的桌子

成了一个集会区、服务区。

11 各种材质搭配

在景观上,包括很多不同的植物类型和材质,

现代简约的风格可以减弱你的劳动力。

小额量的工作有助于调节生命活动。

12 移动你周边的空气

庭院,本来能起到庇护的原理作用,

但不幸的是,却挡住了夏天凉爽的微风。

如果你有一个开放式的结构、

一个真正的屋顶或棚架,

你可以在其顶上设置一个吊扇,

它可以帮忙降低高达10度的温度。

在吊扇边装一盏灯,

还将有一个可靠的架空照明光源。

13 利用植物的质地

在结构或是硬件改变或是匮乏的情况下,

植物能够通过增加一种鲜活的方式

去迎合庭院的景观。

植物集中体现了景物在色调和风格上的多样性。

14 添加小水景

即使是一个小小的喷泉或水盆,

招来了一只只小鸟的宛转动听的清脆声音,

吸引蝴蝶翩翩起舞。

娇小的水功能,

也可以成为圆形庭院的一个迷人的焦点。

八、学习安卓开发,有没有好的入门教程!?

随着时代的进步,Android平台被广泛推广以来,越来越多的人进入到了Android开发行业。有人认为,Android开发市场已经饱和,不适合发展,但是小编认为,的android开发工程师和普通的还是有很大差别的。目前,在整个产业链中,Android开发人才仍是国内薄弱的环节,安卓开发行业对技能人才需求很大!目前Android开发人才仍有很大缺口,所以,现在做Android开发还为时未晚。

下面小编就与大家分享一下Android开发每个阶段以及需要掌握的内容有哪些。

1.Android基础阶段

主要需要掌握的技能

  • 架构设计必入技能(注解、泛型)
  • 架构动态编程技术原理
  • Android虚拟机指令
  • Android虚拟机垃圾回收
  • Android虚拟机类和对象的结构
  • 并发内存模型
  • synchronize机制
  • 深入并发原理只线程池
  • 高效IO与数据序列化

2.Android开发核心部分

主要需要掌握的技能

  • UI优化
  • 启动优化
  • 崩溃优化
  • 卡顿优化
  • 安全性优化
  • 弱网优化
  • APP深度优化
  • 开发焦点问题优化
  • 编程效率优化

3.Framework与Android 内核

主要需要掌握的技能

  • Framework通信
  • Framework底层服务
  • Framework系统资源
  • Framework事件机制
  • Framework UI机制
  • Framework 实战与总结

4.Android音视频

主要需要掌握的技能

  • C与C++基础语法
  • H264编码基础
  • H264编码进阶
  • H265编码原理
  • H265编码应用
  • MediaCodec硬解码(联发科与高通)
  • Media内核源码
  • ...

5.Android资深架构师

主要需要掌握的技能

  • 架构师通用技能
  • 网络访问
  • 图片加载
  • 进程通信框架
  • Rx响应式编程
  • 注入解耦
  • 组件化结构设计
  • ...

6.Flutter高级工程师

主要需要掌握的技能

  • Dart语法基础
  • Dart语法进阶
  • Flutter3.0之UI
  • Flutter3.0线程
  • Flutter启动流程
  • Flutter3.0 FrameWork框架
  • Flutter性能监控

7.Android车载工程师

主要需要掌握的技能

  • 蓝牙通信
  • 串口
  • DLNA
  • Automotive系统
  • 车载进程通信
  • CarLauncher开发
  • 车载多媒体
  • ...

8.Android前言技术

主要需要掌握的技能

  • 自动化构建App
  • 前言编译插件技术
  • Compose基础
  • Compose进阶

以上是小编为大家分享的关于安卓开发每个阶段需要学习技术。关于安卓开发,小编这里准备的一套2023年可能会遇到的面试题,感兴趣的同学可以点击查看。谢谢各位的支持。

2023年Android精选面试题https://docs.qq.com/doc/DWGZIRFh5VEtYWE1D

九、暖通设计新手入门教程?

1、倾斜式微压计:设有滤毒通风的防空地下室,应在防化通信值班室设置测压装置。该装置可由倾斜式微压计、连接软管、铜球阀和通至室外的测压管组成。测压管应采用DN15热镀锌钢管,其一端在防化通信值班室通过铜球阀、橡胶软管与倾斜式微压计连接,另一端则引至室外空气零点压力处,且管口向下。

2、排烟口或排烟阀平时为关闭时,应设置手动和自动开启装置,一般距地1.5m;

3、散热器高阻恒温控制阀:当室内供暖系统为垂直或水平双管系统时,应在每组散热器的供水支管上安装高阻恒温控制阀;超过5层的垂直双管系统宜采用有预设阻力调节功能的恒温控制阀。恒温阀有个5℃的防冻开度,一般不能关闭,需要在回水管上设置关断阀。

4、汽车库内设CO浓度监控(CO探测点):地下停车库风机宜采用多台并联方式或设置风机调速装置,并宜根据使用情况对风机设置定时启停(台数)控制或根据车库内的CO浓度进行自动运行控制。一氧化碳的短时间接触容许浓度上限为30 mg/m3。例如:当CO浓度超过30 mg/m3时,发出报警信号,并联动控制车库通风风机进行开启控制;当CO浓度低于27 mg/m3时,联锁关闭风机。

5、地暖盘管的伸缩缝:当地面面积超过30m2或边长超过6m时,应按不大于6m间距设置伸缩缝,伸缩缝宽度不应小于8mm;伸缩缝宜采用高发泡聚乙烯泡沫塑料板,或预设木板条待填充层施工完毕后取出,缝槽内满填弹性膨胀膏。

塑料管弯曲半径不应小于管道外径的8倍,当盘管转弯半径不满足规范要求时,有经验的安装工人,会局部调整盘管的间距,使转弯半径到达规范要求,具体如下:

6、立式除污器:管道管径DN≤100宜选用Y型过滤器,管径DN≥150宜选用蓝式过滤器或除污器。

7、自动排气阀,具体设置要求如下:

自动排气阀在双管系统支管的立管中设置,由于设置过多,漏水的隐患很大。原因:室内热水供暖系统循环水的水质受到小区换热站内的设备状况影响,小区换热站一般没有除氧及离子交换装置,只是在系统总回水干管上设置一个简单的除污器,无法从根本上控制水质。基于这种情况,系统内不洁的循环水将腐蚀管路,使钢管从内部层层脱皮,当水中的污物卡到自动排气阀的密封端面上时,便产生漏水,这是漏水的最主要原因。对策:1)如果在自动排气阀上接排水管,接到排水处。2)自动排气阀前加设Y型过滤器或除污器。如果不能很好的解决排水,就只在散热器设置手动放气阀。

8、挡烟垂壁:应采用不燃材料制作,如钢板、夹胶玻璃、钢化玻璃等。从顶棚下垂不小于500mm的固定或活动的挡烟设施。

9、超压排气活门:建议选用PS-D250型号,其竖向间距应大于等于600mm,水平向间距宜大于等于550mm,顶边距顶板大于等于150mm;为防止被意外破坏,超压排气活门应安装在较高的位置。

10、车库排烟风管尽量不穿人防墙,到防护门结束(非人防区到防护门距离小于30m时)。穿过防空地下室顶板、临空墙和门框墙的管道,其公称直径不宜大于150mm。

11、过滤吸收器:RFP-1000型过滤吸收器:①尺寸为870x623x623,进出口直径为315mm;阻力为850Pa;②垂直方向:中心距地不小于500mm,两者中心垂直之间不小于1000mm;③水平方向:中心距墙不小于700mm,两者中心水平之间不小于1300mm(检修要求);

12、隔油池排风:>6次/h,补风取排风的90%,单独排风、高空排风,有些地方要求做防爆风机(废气产生易爆气体如甲烷等)

13、防止冷风渗透的措施:对于严寒地区公共建筑经常开启的外门,应采用热空气幕等减少冷风渗透的措施;对于寒冷地区公共建筑经常开启的外门,当不设门斗和前室时,宜设置热空气幕。

14、空调冷凝水管:冷凝水排入污水系统时,应有空气隔断措施;冷凝水管不得与室内雨水系统直接连接;对于高级别酒店,冷凝水应收集后统一排放。

十、求android开发快速入门教程,有基础但生疏了?

看文字版本的话我觉得这个还是挺容易上手的。虽然是2018的教程,但是也够用了。基本上能够快速上手。

1.0 Android基础入门教程

如果是看视频教程的话,直接B站搜索2021版的教程,有很多内容。

顶一下
(0)
0%
踩一下
(0)
0%
相关评论
我要评论
用户名: 验证码:点击我更换图片
上一篇:返回栏目