一、android studio入门教程?
如果您想学习Android开发并使用Android Studio作为开发工具,以下是一个简单的Android Studio入门教程:
1. 下载和安装Android Studio:访问官方网站(https://developer.android.com/studio)下载Android Studio,并按照安装向导进行安装。
2. 创建新项目:打开Android Studio,选择“Start a new Android Studio project”创建一个新项目。在创建项目时,您可以选择项目名称、包名、目标设备等。
3. 界面介绍:Android Studio的界面由多个窗口组成,包括代码编辑器、项目结构、控制台等。熟悉这些窗口的功能和布局对于开发非常重要。
4. 编辑布局文件:Android Studio使用XML文件来定义应用的布局。您可以使用布局编辑器来可视化设计界面,也可以直接编辑XML文件。
5. 编写代码:使用Java或Kotlin编写应用的逻辑代码。Android Studio提供代码编辑器和自动补全功能,帮助您提高开发效率。
6. 调试应用:Android Studio提供强大的调试功能,您可以在模拟器或真机上运行应用,并使用调试器进行断点调试、查看变量值等。
7. 构建和运行应用:使用Android Studio的构建工具将应用打包成APK文件,并在模拟器或真机上运行。
8. 学习Android开发知识:Android Studio只是一个工具,学习Android开发的核心知识也非常重要。您可以通过官方文档、在线教程、视频课程等途径学习Android开发的基础知识和最佳实践。
这只是一个简单的入门教程,如果您想深入学习Android开发,建议您参考更详细的教程和资源,以便更全面地了解Android开发的各个方面。祝您学习愉快!
二、Android 开发入门教程有哪些推荐?
反射的概念
- 反射:Refelection,反射是Java的特征之一,允许运行中的Java程序获取自身信息,并可以操作类或者对象的内部属性
- 通过反射,可以在运行时获得程序或者程序中的每一个类型的成员活成成员的信息
- 程序中的对象一般都是在编译时就确定下来,Java反射机制可以动态地创建对象并且调用相关属性,这些对象的类型在编译时是未知的
- 也就是说 ,可以通过反射机制直接创建对象,即使这个对象类型在编译时是未知的
- Java反射提供下列功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法,可以通过反射调用 private 方法
- 在运行时调用任意一个对象的方法
反射调用方法原理
- 首先Java通过字节码获取类的基本信息,其次通过Class#getMethod("myMethod")经过查找获取Method对象
- 接着通过Method#invoke调用方法, 此处包括Native版本和Java版本实现
- Native版本的invoke0()在HotSpot VM里是由JVM_InvokeMethod()支持
- JVM_InvokeMethod()中通过JNIHandles::resolve(method)解析方法的符号引用(个人理解, 详情参考R大博客)
- 拿到method_handle后, 即符号引用, 获取方法的返回类型等相关信息, 最后调用invoke()执行方法(个人理解, 详情参考R大博客)
- 含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 文件
- 检索 action 中 name 为 login 的 Action
- 根据 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,则进行进一步的权限检查:
- 首先用 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
- 获取 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 方法继续检查权限.若检查通过就更新缓存,这样下一次同一个类调用同一个方法时就不用执行权限检查了,这是一种简单的缓存机制
由于 JMM 的 happens-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 的具体实现类:
- sun.reflect.DelegatingMethodAccessorImpl
- sun.reflect.MethodAccessorImpl
- 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 版开始会会生成 NativeMethodAccessorImpl 和 DelegatingMethodAccessorImpl 两个对象
- 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 所引用的 MethodAccessor 为 Java 版
- 经由 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)"的行为
- 即允许应用程序根据调用类或调用栈中的其它类来改变其自身的行为
反射注意点
- 反射会额外消耗系统资源,如果不需要动态地创建一个对象,就不要使用反射
- 反射调用方法时可以忽略权限检查.可能会破坏封装性而导致安全问题
三、求android开发快速入门教程,有基础但生疏了?
看文字版本的话我觉得这个还是挺容易上手的。虽然是2018的教程,但是也够用了。基本上能够快速上手。
如果是看视频教程的话,直接B站搜索2021版的教程,有很多内容。
四、Android起源?
2003年10月,Andy Rubin等人创建Android公司,并组建Android团队。
2005年8月17日,Google低调收购了成立仅22个月的高科技企业Android及其团队。安迪鲁宾成为Google公司工程部副总裁,继续负责Android项目。
2007年11月5日,谷歌公司正式向外界展示了这款名为Android的操作系统,并且在这天谷歌宣布建立一个全球性的联盟组织,该组织由34家手机制造商、软件开发商、电信运营商以及芯片制造商共同组成。
并与84家硬件制造商、软件开发商及电信营运商组成开放手持设备联盟来共同研发改良Android系统,这一联盟将支持谷歌发布的手机操作系统以及应用软件,Google以Apache免费开源许可证的授权方式,发布了Android的源代码。
2008年,在GoogleI/O大会上,谷歌提出了AndroidHAL架构图,在同年8月18号,Android获得了美国联邦通信委员会(FCC)的批准,在2008年9月,谷歌正式发布了Android 1.0系统,这也是Android系统最早的版本。
五、Android Studio设置或修改Android SDK路径?
方法是:
1、比如你要把AVD放在D盘AndroidAVD下面,则预先在D盘下建立一个文件夹 AndroidAVD。必须的。不然设置了环境变量也没有用,因为模拟器不会自动创建该文件夹。
2、在桌面右击“我的电脑”选择“属性”,进入“高级----环境变量-----系统变量----新建“,从而新建一个环境变量ANDROID_SDK_HOME,变量值设置为:D:\AndroidAVD。如图所示。一路确定下来,保存环境变量。重新启动计算机。
3、如果你以前没有AVD,则启动AVD Manager新建一个AVD,则文件会全部保存到 D:\AndroidAVD下面。第4点不用看了。
4、如果你以前有AVD,改了路径后想继续用,则要把原来C:\Documents and Settings\Administrator\.android\avd下面的全部文件夹复制到 D:\AndroidAVD下面,把avd下面的.ini文件里面的路径 C:\Documents and Settings\Administrator\.android\avd部分全部改成D:\AndroidAVD\.android\avd。再进一个以.AVD结尾的文件夹改下面的hardware-qemu.ini这个文件里面的路径 C:\Documents and Settings\Administrator\.android\avd部分全部改成D:\AndroidAVD\.android\avd。
这2个ini文件里面的路径不改光复制文件过去没有用的,AVD Manager会报错且会删除复制过来的所有avd文件,但并不会删除和影响C:\Documents and Settings\Administrator\.android\avd下面的文件。
为保险,建议新的AVD启动正常能进安卓系统了以后,再把原来C:\Documents and Settings\Administrator\.android\avd下面的所有文件删除即可。
六、android开发语言?
如果你想开发一个Android应用程序,你可能想利用java、Kotlin、C++、C语言或Lua来给你的应用程序带来成功的最佳机会。
1.JAVA
JAVA被视为官方的Android开发编程语言。由于内置的开放源码库可供用户选择,JAVA易于处理,并提供了最佳的文档和社区支持。其丰富的功能让您可以自由开发最佳的跨平台应用程序、Android应用程序、游戏、服务器应用程序、嵌入式空间、网站等。
因此,JAVA也是使用最广泛的语言。许多PlayStore应用程序都是用JAVA构建的,它也是Google最支持的语言。JAVA还提供了一个很好的在线社区,在出现任何问题时提供支持。
然而,JAVA对于初学者来说是一种复杂的语言,因为它包含复杂的主题,如构造函数、空指针异常、并发性、标记异常等。此外,Android软件开发工具包(SDK)将复杂性提升到了一个新的水平。
总的来说,JAVA是体验Android应用程序开发所有乐趣的绝佳语言。
2.Kotlin
据说Kotlin是Java的高级版本,是一种用于开发现代Android应用程序的统计编写的编程语言。Kotlin也被认为是应用程序的最佳语言。Kotlin有可能影响其他编程语言,如JAVA,以创建健壮和高性能的应用程序。Kotlin内置的一些流行应用程序有Coursera、Trello、Evernote等。
Java和Kotlin之间唯一显著的区别是Kotlin删除了多余的Java特性,例如空指针异常。简单地说,从程序员的角度来看,Kotlin比Java更容易让初学者进行测试,也可以作为Android应用程序开发的“入口点”。
3.C++
C++是许多顶级移动应用开发公司的首选。它是一种通用的、面向对象的语言,具有通用性和低级别内存操作的特性。
用于Android应用程序开发和本地应用程序,C++可以开发游戏、基于GUI的应用程序、实时数学模拟、银行应用程序等等。C++在云计算应用中很受欢迎,因为它可以很快适应硬件或生态系统的变化。
C++可以用于Android应用程序开发,使用原生Android开发工具包(NDK)。但是,应用程序不能完全使用C++来创建,NDK用于实现本地C++代码中应用程序的部分。它有助于在需要时使用C++代码库作为应用程序。
虽然C++在某些情况下对Android应用程序开发很有用,但是配置更难,灵活性也就差得多。由于复杂性的增加,它还可能产生更多的错误。因此,最好使用java与C++相比,因为它不能提供足够的增益来弥补所需的努力。
4.C#
C#与Java非常相似,非常适合Android应用程序开发。与Java一样,C#也实现垃圾收集,因此内存泄漏的可能性较小。C#还有更简洁的语法,这使得编码相对容易。
以前,C#最大的缺点是它只能在Windows系统上运行,因为它使用.NET框架。然而,这个问题是由Xamarin处理的,Xamarin是公共语言基础设施的跨平台实现。现在,Xamarin.Android工具可以用来编写原生Android应用程序,并跨多个平台共享代码。
C#被称为“C-sharp”,作为一种广泛用于移动开发(主要用于Windows跨平台应用程序开发)的通用、面向对象编程语言,在市场上占有显著地位。
如果您计划开发高性能和交互式游戏应用程序,这是最好的语言。
5.Lua
Lua是一种跨平台的多范式编程语言。它是一种重量轻、移动第一的企业通信解决方案。Lua为企业内置的消息传递提供了强大的支持,它是即时的、安全的,并使开发人员对其负责。
由于实时安全消息、分析仪表板、轻松的文件共享和双触式电话会议,这种语言变得流行起来。如果您希望提高应用程序的可移植性、速度、可靠性和可扩展性,Lua是一个完美的选择。
使用上述编程语言可以创建许多应用程序,如聊天信使、音乐播放器、游戏、计算器等。正如你所知,没有一种语言可以被称为“正确的语言”
因此,根据每个项目的目标和偏好,选择正确的语言取决于您自己。与合适的Android应用程序开发公司取得联系,为您的企业带来成功的礼物。
七、android是什么?
Android是谷歌推出的手机操作系统,就是通常说的安卓,就像电脑上的windows一样,只不过它是基于开源的Linux操作系统开发而来。目前在智能手机、平板、电视、汽车中都有应用,而且装机量也远远高于其他系统。
我们经常听到国内厂商谈论自己的系统或者UI,譬如EMUI、flymeOS、MIUI、Color OS,其实他们的核心都是一样的,手机厂商生产硬件,系统软件都是通过修改Android操作系统来的。只不过有的厂商修改的内容较多,有的厂商修改的内容较少。
安卓一开始是为按键手机开发的系统,而且并不是谷歌开发的,只是后来被谷歌收购了。第一款Android手机HTC G1就是一款带有滑盖的按键手机,由于搭载安卓系统的手机功能更丰富,HTC借着安卓系统的东风风光了几年。
每年谷歌都会召开GoogleI/O大会,发布以甜品命名的安卓系统,最近谷歌宣布放弃这种命名方式,改用数字来命名,经过10多年的发展,目前版本已经达到Android 10。
八、android启动很慢?
目前安卓启动很慢的确实如此,版本越更新的安卓就要求配置高的硬件,每个定制的安卓系统快慢都是不一样的,定制系统的安卓优化越好就越来越流畅,反之就卡顿很多了,安卓系统和windows系统不一样的,微软系统更好的适配各种由硬件组装成的计算机并且发挥它的最好性能,则安卓不一样,在硬件上不自由。
九、android什么软件?
android是一款手心输入法工具的软件,android这款软件支持九宫格拼音键盘,全键盘拼音键盘,英文键盘,数字键盘以及符号键盘等等,不仅包含了一般输入法的中英文输入,词库,皮肤等等功能,同时在功能上做了多项创新与改进拥有强大的智能输入引擎。
十、android 操作原理?
1、接上电源线或者电池,通过充电芯片输出主供电 VPH PWR、 BATT SYS。
2、主电源给开机键提供开机信号电压。
盘等。
3、按开机键产生开机信号送到主电源芯片,电源芯片工作,输出供电给CPU、暂存、硬
电源开启 BOOST芯片,将主供电转换输出辅助供电 PP BUCK BOOST。
4、主电源给晶振供电,晶振产生192MHz38.4MHz频率给电源芯片。
5、主电源输出时钟信号CLK给CPU
6、主电源芯片发出复位信号,复位CPU,CPU再复位字库。
7、CPU发出供电维持信号给主电源芯片,使主电源芯片维持供电正常输出。
8、应用CPU读取硬盘自检数据,对CPU本体、暂存、GPU进行自检。
9、CPU开启显示电路工作、CPU发出显示数据给显示屏,显示屏显示LOGO图标
10、CPU读取硬盘系统程序,并加载 android系统。
11、CPU开启触摸、音频、WFi等其它设备模块工作。
12、CPU启动射频部分工作(射频1C、功放、天线开关)。
13、基带CPU读取SIM卡信息
14、信号接收通道工作,并根据SM卡信息,选择运营商
15、信号发射通道工作,与基站进行连接确认,并显示信号强度
16、手机到此开机完毕。