kuky_xs

Results 44 comments of kuky_xs

- compileSdkVersion 告诉 Gradle 用哪个版本的 Android SDK 编译你的应用,使用任何新添加的 API 就需要使用对应 Level 的 Android SDK。修改 compileSdkVersion 不会改变运行时的行为,当修改了 compileSdkVersion 时可能会出现新的编译警告、编译错误,强烈推荐总是使用最新的 SDK 进行编译,避免弃用的 API。此外,如果使用最新发布的 Support Library 就需要使用最新的 SDK 编译。例如使用 23.1.1 版本的 Support Library,compileSdkVersion...

需要,new某个对象,可以分解为: 1 memory=allocate();// 分配内存 相当于c的malloc 2 ctorInstanc(memory) //初始化对象 3 instance=memory //设置instance指向刚分配的地址 在编译器运行时,可能会出现重排序 从1-2-3 排序为1-3-2 如此在多线程下就会出现问题例如现在有2个线程A,B 线程A在执行第5行代码时,B线程进来,而此时A执行了 1和3,没有执行2, 此时B线程判断instance不为null 直接返回一个未初始化的对象,就会出现问题 而用了volatile,上面的重排序就会在多线程环境中禁止,不会出现上述问题。

概念:锁池和等待池:一、锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。二、等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中。 notify和notifyAll的区别:一、如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。 二、当有线程调用了对象的notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。 三、优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

使用共享变量的方式 在这种方式中,之所以引入共享变量, 是因为该变量可以被多个执行相同任务的线程用来作为是否中断的信号,通知中断线程的执行。 使用interrupt方法终止线程 如果一个线程由于等待某些事件的发生而被阻塞, 比如当一个线程调用Thread.join()方法,或者Thread.sleep()方法, 在网络中调用ServerSocket.accept()方法时,都有可能导致线程阻塞,即使主程序中将该线程的共享变量设置为true,但该线程此时根本无法检查循环标志,当然也就无法立即中断。 使用Thread提供的interrupt()方法,该方法不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码

使用共享变量的方式 在这种方式中,之所以引入共享变量,是因为该变量可以被多个执行相同任务的线程用来作为是否中断的信号,通知中断线程的执行。 使用interrupt方法终止线程 如果一个线程由于等待某些事件的发生而被阻塞,又该怎样停止该线程呢?这种情况经常会发生,比如当一个线程由于需要等候键盘输入而被阻塞,或者调用Thread.join()方法,或者Thread.sleep()方法,在网络中调用ServerSocket.accept()方法,或者调用了DatagramSocket.receive()方法时,都有可能导致线程阻塞,使线程处于处于不可运行状态时,即使主程序中将该线程的共享变量设置为true,但该线程此时根本无法检查循环标志,当然也就无法立即中断。这里我们给出的建议是,不要使用stop()方法,而是使用Thread提供的interrupt()方法,因为该方法虽然不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码。

不可变对象(Immutable Objects)即对象一旦被创建它的状态(对象的数据,也即对象属性值)就不能改变,反之即为可变对象(Mutable Objects)。 不可变对象的类即为不可变类(Immutable Class)。Java平台类库中包含许多不可变类,如String、基本类型的包装类、BigInteger和BigDecimal等。 不可变对象天生是线程安全的。它们的常量(域)是在构造函数中创建的。既然它们的状态无法修改,这些常量永远不会变。 不可变对象永远是线程安全的。 只有满足如下状态,一个对象才是不可变的; 它的状态不能在创建后再被修改; 所有域都是final类型; 并且,它被正确创建(创建期间没有发生this引用的逸出)。

反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。 通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。 反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。 Java 反射主要提供以下功能: - 在运行时判断任意一个对象所属的类; - 在运行时构造任意一个类的对象; - 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法); - 在运行时调用任意一个对象的方法 重点:**是运行时而不是编译时** 反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。 由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。...

```java /** * 实现一个特殊的栈,在实现栈的基本功能的基础上,在实现返回栈中最小元素的操作。 要求: 1. pop、push、getMin操作的时间复杂度都是O(1) * 2. 设计的栈类型可以使用现成的栈结构 */ public class Problem01_GetMinStack { public static class MyStack1 { /** * 两个栈,其中stacMin负责将最小值放在栈顶,stackData通过获取stackMin的peek()函数来获取到栈中的最小值 */ private Stack stackData; private Stack stackMin;...

SharedPreferencesImpl 会将 File 文件在子线程全部加载解析到一个内存的 Map 中,而 SharedPreferences 对象又会被 ContextImpl 的 static Map 进程 Cache 操作,所以 SharedPreferencesImpl 就相当于是一个单例存储的,故而其 Map 在内存中就会持续存在,即便使用 Editor 进行修改后 commit 操作实质也是对 SharedPreferencesImpl 中 Map 进行对应操作。 ```java //一个SharedPreferences的get操作与Editor操作对应的内存Map操作原理 final...

由于字符串在 Java 中是不可变的,如果你将密码存储为纯文本,它将在内存中可用,直到垃圾收集器清除它. 并且为了可重用性,会存在 String 在字符串池中, 它很可能会保留在内存中持续很长时间,从而构成安全威胁。由于任何有权访问内存转储的人都可以以明文形式找到密码,这是另一个原因,你应该始终使用加密密码而不是纯文本。由于字符串是不可变的,所以不能更改字符串的内容,因为任何更改都会产生新的字符串,而如果你使用char[],你就可以将所有元素设置为空白或零。因此,在字符数组中存储密码可以明显降低窃取密码的安全风险。