首页 文章 精选 留言 我的

精选列表

搜索[android things],共10000篇文章
优秀的个人博客,低调大师

我要做 Android 之 Java 基础

Q:面向对象编程的四大特性及其含义? 首先四大特性是:封装,继承,多态,抽象 什么是封装? 就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。 封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口。 通俗点即隐藏信息 提供使用接口给别人使用,不让别人直接操作属性或方法。 什么是继承? 继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。 其中父类又叫超类或基类,子类又叫派生类。父类是子类的一般化,子类是父类的特化(具体化)。 转型: 向上转型:子类引用的对象转换为父类类型称为向上转型。 通俗地说就是是将子类对象转为父类对象。 此处父类对象可以是接口 向下转型:父类引用的对象转换为子类类型称为向下转型。 情况一:如果父类引用的对象如果引用的是指向的子类对象,那么在向下转型的过程中是安全的。也就是编译是不会出错误的。 什么叫多态? 多态的概念即“一个接口,多个方法” 多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。 其中,方法的重写Overriding和重载Overloading是Java多态性的不同表现 方法重载:是统一各类中写有多个同名方法。 但其中的参数个数、顺序、类型不同 返回值类型、修饰符均没关系 方法重写:是子类继承父类,子类重写父类同名方法。 方法名和参数必须一致 返回值类型也必须和父类方法的返回值类型一致 范围修饰符子类的要比父类的大或等于 什么是抽象? 抽象就是把一个对象分析出各个属性,来替代表达的手法 。 抽就是抽离;象 表象,即表示出来的部分 abstract 关键字 abstract(抽象)可以修饰类、方法 抽象方法:在类中没有方法体的方法,就是抽象方法。 抽象方法的定义: abstract 返回值类型 方法名(); 抽象类:含有抽象方法的类就叫抽象类。 抽象类的定义: abstract class 类名{} 1 用abstract关键字来修饰一个类时,这个类叫做抽象类; 用abstract来修饰一个方法时,该方法叫做抽象方法。 2 含有抽象方法的类必须被声明为抽象类, 抽象类必须被继承,抽象方法必须被重写。 3 抽象类不能被实例化。 4 抽象方法只需声明,而不需实现某些功能。 接口的特点: A,接口中一般定义的是常量和抽象方法。 抽象类中可以包含抽象方法,也可以有非抽象方法, 但是有抽象方法的类一定是抽象类。抽象方法不能有方法体。 B,接口(interface)中,方法只能定义抽象方法而且默认是Public, 常量则是public static final 修饰的 (不管有没有这些修饰符,方法和常量默认具这种属性)。 C,一个类可以实现多个无关的接口(这点和继承要有所区别)。 D,接口可以继承其他的接口,并添加新的属性和抽象方法。 E,在类中实现接口的方法时必须加上public修饰符。 接口和抽象类的区别: (1)相同点 A,两者都是抽象类,都不能实例化。 B,interface实现类及abstrct class的子类都必须要实现已经声明的抽象方法。 (2)不同点 A,interface实现,要用implements,而abstract class的实现,要用extends。 B,一个类可以实现多个interface,但一个类只能继承一个abstract class。 C,interface强调特定功能的实现,而abstract class强调所属关系。 D,尽管interface实现类及abstrct class的子类都必须要实现相应的抽象方法,但实现的形式不同。 E,interface是完全抽象的,只能声明方法,而且只能声明pulic的方法,不能声明private及protected的方法,不能定义方法体,也不能声明实例变量。 Q:String、StringBuffer和StringBuilder的区别 String:字符串常量 。StringBuffer 与 StringBuilder是字符缓冲变量。StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer中的方法大都采用了synchronized 关键字进行修饰,因此是线程安全的,而StringBuilder没有这个修饰,可以被认为是线程不安全的。StringBuilder 是在JDK1.5才加入的。 注意:从JDK1.5开始,带有字符串变量的连接操作(+),JVM 内部采用的是 StringBuilder 来实现的,而之前这个操作是采用 StringBuffer 实现的。 1、String类型的字符串对象是不可变的,一旦String对象创建后,包含在这个对象中的字符系列是不可以改变的,直到这个对象被销毁。 2、StringBuilder和StringBuffer类型的字符串是可变的,不同的是StringBuffer类型的是线程安全的,而StringBuilder不是线程安全的 3、如果是多线程环境下涉及到共享变量的插入和删除操作,StringBuffer则是首选。如果是非多线程操作并且有大量的字符串拼接,插入,删除操作则StringBuilder是首选。毕竟String类是通过创建临时变量来实现字符串拼接的,耗内存还效率不高,怎么说StringBuilder是通过JNI方式实现终极操作的。 总的来说,三者在执行速度方面的比较:StringBuilder > StringBuffer > String。 Q:String a=""和String a=new String("")的的关系和异同? 1. String是一个对象。 因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。 2. new String()和new String(“”)都是申明一个新的空字符串,是空串不是null; 先简单引入常量池这个简单的概念。 常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。 用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。 5. 关于equals()和==: 这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。 2.复合数据类型(类) 当他们用( == )进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。 对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号( == )进行比较的,所以比较后的结果跟双等号(==)的结果相同。 Q:装箱、拆箱什么含义? Java 中装箱和拆箱指的是基本数据类型和包装类型的自动相互转换,他为开发者提供了方便。开发人员也可以不使用它,而手动的进行类型转换。这个类型转换在编译阶段。 Q:int和Integer的区别? int与integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象 Q:遇见过哪些运行时异常?异常处理机制知道哪些? 当一个程序出现错误时,可能是以下三种错误: 语法错误:如缺少必要的标点符号、关键字输入错误、数据类型不匹配等,在编译器对程序进行编译的过程中,会把检测到的语法错误以提示的方式列举出来,故又称为编译错误。 运行时错误:如空指针异常,数组越界,除数为零、数据库连接失败等,迫使程序终止,有特定的发生条件。 逻辑错误:在语法上是有效的,但是在逻辑上是错误的,此类问题不好调试。 这里说的Java异常处理机制主要是指处理运行时错误。 a.Throwable继承层次结构,可见分成两大类Error和Exception。 01.jpg Error (错误):指程序无法恢复的异常情况,表示运行应用程序中较严重的问题。 发生于虚拟机自身、或者在虚拟机试图执行应用时,如Virtual MachineError(Java虚拟机运行错误)、NoClassDefFoundError(类定义错误)。 属于不可查异常,即不强制程序员必须处理,即使不处理也不会出现语法错误。 Exception (异常):指程序 有可能恢复的异常情况,表示程序本身可以处理的异常。又分两大类: RuntimeException (运行时异常):由程序自身的问题导致产生的异常。 如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)。 属于不可查异常。 非运行时异常:由程序外部的问题引起的异常。 除了RuntimeException以外的异常,如FileNotFoundException(文件不存在异常)。 属于可查异常,即强制程序员必须进行处理,如果不进行处理则会出现语法错误。 02.png b.异常处理机制 (1)捕捉异常:由系统自动抛出异常 try 捕获异常:用于监控,若发生异常,会抛出异常类所产生的对象并立刻结束执行,并转向异常处理catch块。 catch 处理异常:若抛出的异常对象属于catch内所定义的异常类,则进入catch中的对应代码段继续运行程序,反之进入finally块。常用方法: e.getMessage():返回异常对象的一个简短描述 e.toString():获取异常对象的详细信息 e.printStackTrace():在控制台上打印异常对象和它的追踪信息 finally 最终处理:无论是否捕获或处理异常,finally块里的语句都会被执行。在以下4种特殊情况下,finally块才不会被执行: 在finally语句块中发生了异常 在前面的代码中用了System.exit()退出程序 程序所在的线程死亡 关闭CPU try { // 可能会发生异常的程序代码 } catch (异常类1 异常变量) { // 捕获并处理try抛出的异常类型Type1 } catch (异常类2 异常变量) { // 捕获并处理try抛出的异常类型Type2 } finally { // 无论是否发生异常,都将执行的语句块 } 注意: 一个try、catch、finally之间不能插入其它代码 catch可有多个,try和finally只能有一个 try后面必须至少跟着catch和finally其中的一个 (2)抛出异常:在方法中将异常对象显性地抛出,之后异常会沿着调用层次向上抛出,交由调用它的方法来处理。 throws:声明抛出的异常,位置在方法名后、异常类型前 throw:抛出异常,一般在方法体内部 (3)自定义异常:继承Execption类或其子类,实现步骤如下: 声明自定义异常类并继承Exception,可重写方法如getMessage() 在方法头用throws声明该方法可能抛出的异常 在方法体的适当位置创建自定义异常类对象,并用throw将异常抛出 调用该方法时,对可能产生的异常进行捕获,并处理异常 //1.自定义的异常类 class MyException extends Exception { String message; public MyException(String ErrorMessagr) { super(ErrorMessagr) ; } public String getMessage() { return message; } } public class Demo { public static void main(String[] args) { //4.调用方法时捕获和处理 try { test(); } catch (MyException e) { System.out.println(e.getMessage()); e.printStackTrace(); } } //2.在方法头声明可能出现的异常 public static void test() throws MyException{ try { int i = 10/0; System.out.println("i="+i); } catch (ArithmeticException e) { //3.在适当情况下抛出异常 throw new MyException("This is MyException"); } } } Q:什么是反射,有什么作用和应用? Java基础之泛型&反射 a.泛型 含义:是JDK1.5的新特性,本质是参数化类型,即所操作的数据类型被指定为一个参数,使用时通过传参来指定具体的类型。 好处:安全简单。具体体现在提供编译时的强类型检查,而不用等到运行;可避免类类型强制转换;增强代码可读性。 //不使用泛型需要强制转换 List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0) //使用泛型可避免强制转换 List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); 以上例子也能看到在集合类使用泛型的情况很普遍,而且相比于数组具有动态的特点。 类型 :通过创建位置的不同,分可为 泛型类:public class 类名<泛型类型1,…> 泛型方法:public <泛型类型1,…> 返回类型 方法名(泛型类型1 参数名1,…) 泛型接口:public interface 接口名<泛型类型1,…> 下面分别举例说明。 //泛型类:把泛型定义在类上 public class ObjectTool<T> { private T obj; public T getObj() { return obj; } public void setObj(T obj) { this.obj = obj; } } //测试 public class ObjectToolDemo { public static void main(String[] args) { ObjectTool<String> ot1 = new ObjectTool<String>(); ot1.setObj(new String("Jiwenjie")); System.out.println("姓名是:" + ot1.getObj()); //姓名是:Jiwenjie ObjectTool<Integer> ot2 = new ObjectTool<Integer>(); ot2.setObj(new Integer(21)); System.out.println("年龄是:" + ot2.getObj()); //年龄是:21 } } //泛型方法:把泛型定义在方法上 public class ObjectTool { public <T> T show(T t) { if (t != null){ return t; }else{ return null; } } //测试 public class ObjectToolDemo { public static void main(String[] args) { ObjectTool ot = new ObjectTool(); System.out.println(ot.show("Jiwenjie"));//Jiwenjie System.out.println(ot.show(21));//21 } } //泛型接口:把泛型定义在接口上 public interface ObjectTool<T,U> { void show(T t,U u); } class ObjectToolTest implements ObjectTool<String,Date> { @Override public void show(String str,Date date) { System.out.print(str); System.out.print(date); } } //测试 public class ObjectToolDemo { public static void main(String[] args) { ObjectToolTest test = new ObjectToolTest(); test.show("Hello",new Date());//Hello当前时间 } } 泛型变量的类型限定:使用extends关键字,限定的是形式参数 如public class ObjectTool<T extends Number>表示只接受Number类或其子类的参数 通配符?的边界限定 :并配合 extends 和 super 关键字,限定的是 实际参数 未受限List<?> :等效于List<? extends Object> 上边界限定List<? extends Number> :表示不确定参数类型,但一定是Number类或其子类的类型 下边界限定List<? super Number> :表示不确定参数类型,但一定是Number类或其父类的类型 如 List<? extends Number> list =new ArrayList<Integer>();表示创建元素对象都是Integer的List 泛型擦除:清除泛型类型参数的相关信息,并且在必要的时候添加类型检查和类型转换的方法。即泛型java代码->普通java代码 //擦除前 class Pair<T> { private T value; public T getValue() { return value; } public void setValue(T value) { this.value = value; } } //擦除后 class Pair { private Object value; public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } } 使用限制: //不能用基本类型实例化泛型 Pair<int, char> p = new Pair<>(8, 'a'); // error Pair<Integer, Character> p = new Pair<>(8, 'a'); // ok //不能用static修饰泛型类型 public class MobileDevice<T> { private static T os; // error } //不能对参数化类型使用Casts,除非是无界通配符类型 List<Integer> li = new ArrayList<>(); List<?> list = li; // ok List<Number> ln = (List<Number>) li; // error //不能对参数化类型使用instanceof,除非是无界通配符类型 public static <E> void rtti(List<E> list) { if (list instanceof ArrayList<Integer>) { // error } if (list instanceof ArrayList<?>) { // OK } } //不能创建参数化类型的数组 ArrayList<String>[] arrayOfList = new ArrayList<String>[3]; // error //不能创建、捕捉或抛出参数化类型的对象 class MathException<T> extends Exception {} // error class QueueFullException<T> extends Throwable {} // error public static <T extends Exception, J> void execute(List<J> jobs) { try { } catch (T e) { // error } } //不能重载参数类型为相同原始类型的方法,因为擦除后是一样的 public class Example { // error public void print(List<String> list) {} public void print(List<Integer> list) {} } 重点重点: b.反射 含义:在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任何一个对象都能够调用它的任何一个方法和属性。 功能 :动态性 在运行时判断任意一个类所具有的属性和方法 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时调用任意一个对象的方法 生成动态代理 java.lang.Class :实现反射的 基础 原因 JVM每创建一个类都会产生一个对应Class对象,并把它保存在同名.class文件。有关类加载机制 Java反射包java.lang.reflect中的所有类都没有public构造方法,只能通过Class类获得这些类的实例 获取Class对象的方法 .class:通过类的类型,基本类型可以使用 Object.getClass():通过对象实例,注意基本数据类型无法使用 Class.forName():通过类的全限定名,注意基本数据类型无法使用 Class c1 = Test.class; Class c2 = test.getClass();// test是Test类的一个对象 Class c3 = Class.forName("com.catchu.me.reflect.Test"); java.lang.reflect.Member :反射操作的对象。提供三个实现类可在运行时改变对象状态: Constructor :对应类成员中的构造函数 Field :对应类成员中的变量 Method :对应类成员中的方法 在Class提供多种方法可以获取给定类的Constructor、Field和Method,方法如下图 03.png 性能问题。因为反射是在运行时而不是在编译时,所有不会利用到编译优化,同时因为是动态生成,因此,反射操作的效率要比那些非反射操作低得多。 安全问题。使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了。 代码问题。由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。 Q:什么是内部类?有什么作用?静态内部类和非静态内部类的区别? 某种程度上,公开的静态的内部类就相当于一个普通的类。静态内部类相对于外部类来说,仅仅只是包含关系,缩小了命名空间,完整类名中多了一个外部类的名称。本质上是两个独立的类,JVM 不知道他们的包含关系。 (1)静态内部类:它相当于外部类的静态成员一样,使用 static 修饰的内部类,它隶属于外部类,使用起来相当于一个独立的外部类。 (2)成员内部类:它相当于外部类普通的成员一样,隶属于外部类的具体对象,在定义它的时候,需要先创建外部类对象,之后在创建它的实例。 (3)局部内部类:它定义在一个方法的方法体中,它往往仅仅作为方法短暂使用,只能访问使用 final 修饰的局部变量。 (4)匿名内部类:它也是定义在方法体中,但是没有一个具体的名字,具有强大的灵活性,工作本质和局部内部类类似。 Q:final、finally、finalize()分别表示什么含义? Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。 final类不能被继承,没有子类,final类中的方法默认是final的。 final方法不能被子类的方法覆盖,但可以被继承。 final成员变量表示常量,只能被赋值一次,赋值后值不再改变。 final不能用于修饰构造方法。 注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。 finally 用于异常捕获中的处理部分。 finalize: finalize是方法名,java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是在垃圾收集器确认一个对象没有被引用时对这个对象调用的。它是在Object类中定义的,因此,所有的类都继承了它。子类覆盖finalize()方法已整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。 Q:Object有哪些公用方法? (1)clone 方法,实现对象的浅复制。只有实现 Cloneable 接口才可以调用该方法。 (2)getClass 方法,用于获得运行时类型 (3)toString 方法,一般在子类中有重写,使用的比较多 (4)finalize 方法,该方法用于释放资源。因为无法确定该方法什么时候会调用,所以很少使用。 (5)equals 方法,一般来说 equals 和 == 是不一样的,但是在 Object 中两者是一样的。子类一般都要重写这个方法。 (6)hashCode 方法,用于哈希查找,可以减少在查找中使用 equals 的次数,重写了 equals 方法一般都要重写 hashCode 方法。这个方法在一些具有哈希功能的 Collection 中可以用到。 (7)wait 方法,就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait 方法一直等待,直到获得锁或者被中断。wait 设定一个超时间隔,如果在规定的时间内没有获得锁就返回。 (8)notify 方法,唤醒在该对象上等待的某个线程 (9)notifyAll 方法,该方法唤醒在该对象上等待的所有线程。

优秀的个人博客,低调大师

我要做 Android 之要点总结

Q:开启一个线程的方法有哪些?销毁一个线程的方法呢? 直接使用Thread类。 使用Runnable和Thread。 使用Runnable和线程池。 使用AsyncTask。 使用HandlerThread。 使用IntentService。 直接使用Thread类开启子线程 这是最简单开启子线程的方法,也是最本质的方法,其他开启子线程的方法都是在此方法基础上的扩展。 一,使用示例如下: new Thread(){ @Override public void run() { super.run(); } }.start(); 使用Thread类开启子线程一共分为三步: 创建Thread的子类对象。 重写run方法。 调用start方法开启子线程。 此时就开启了子线程,run方法执行在子线程中。 使用Runnable接口和Thread类开启子线程 此种方法使用的是Thread类的有参构造创建线程对象。 先实例实现了 Runnable 接口的类,之后在实例化一个 Thread,把接口类作为参数传递进去。之后调用 start 方法即可开启。 使用Runnable和线程池开启子线程 线程池中维护的是线程,所以使用线程池开启子线程本质还是使用的Thread类,因为用到的类和方法不同,所以单独列了出来。 使用示例如下: ExecutorService threadPool = Executors.newFixedThreadPool(5); threadPool.submit(new Runnable() { @Override public void run() { } }); 使用AsyncTask开启子线程 AsyncTask是一个类,里面封装了Thread和Handler,开启了子线程,实现了线程间的通讯。 使用示例 new AsyncTask<String, Integer, Boolean>() { protected void onPreExecute() { super.onPreExecute(); } protected Boolean doInBackground(String... params) { publishProgress(1); return null; } protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); protected void onPostExecute(Boolean result) { super.onPostExecute(result); } }.execute("abc"); 使用HandlerThread开启子线程 HandlerThread是一个类,他继承了Thread类,并重写了run方法,在run方法中使用Looper创建了消息队列,此时就可以在这种Thread中直接使用Handler了。 一,使用示例 HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");; mHandlerThread.start();//开启子线程 Handler mhandler = new Handler(mHandlerThread.getLooper()){ @Override public void handleMessage(Message msg) { //这个方法执行在子线程,里面可以做耗时的操作 } }; mhandler.sendEmptyMessage(10); 分析:由于mHandlerThread.getLooper()得到的是子线程中的looper对象,所以mhandler是子线程中的handler,所以handleMessage方法也执行在子线程。 使用intentService开启子线程 IntentService这是一个特殊的服务,它是一个抽象类,继承了Service。里面封装了HandlerThread和Handler,本质等效于在服务中开启一个子线程。而且这个服务可以在子线程执行结束后自动关闭。 一,使用示例 public static class MyIntentService extends IntentService{ public MyIntentService(String name) { super(name); } @Override protected void onHandleIntent(Intent intent) { //这个方法执行在子线程,里面可以做耗时的操作 } } 分析:自定义一个类,继承intentService,然后重写onHandleIntent方法,这个方法执行在子线程。 Q:Thread的join()有什么作用? thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。 t.join(); //使调用线程 t 在此之前执行完毕。 t.join(1000); //等待 t 线程,等待时间是1000毫秒 volatile和synchronized的区别 volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。 volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的 volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性 volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。 volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化 tips:volitate不是用来同步的,主要还是获取最新数据 同步方法和同步方法块锁住的是谁? 1.同步方法: 即有synchronized (同步,美 ['sɪŋkrənaɪzd] ) 修饰符修饰的方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用给方法前,要获取内置锁,否则处于阻塞状态。 例:public synchronized getMoney(){} 注:synchronized修饰静态方法,如果调用该静态方法,将锁住整个类。 2.同步代码块 即有synchronized修饰符修饰的语句块,被该关键词修饰的语句块,将加上内置锁。实现同步。 例:synchronized(Object o ){} 同步是高开销的操作,因此尽量减少同步的内容。通常没有必要同步整个方法,同步部分代码块即可。 同步方法默认用this或者当前类class对象作为锁。 同步代码块可以选择以什么来加锁,比同步方法要更颗粒化,我们可以选择只同步会发生问题的部分代码而不是整个方法。 Q:sleep()和wait()的区别? 1、每个对象都有一个锁来控制同步访问,Synchronized关键字可以和对象的锁交互,来实现同步方法或同步块。sleep()方法正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sleep指定时间后CPU再回到该线程继续往下执行(注意:sleep方法只让出了CPU,而并不会释放同步资源锁!!!);wait()方法则是指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。(注意:notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度); 2、sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用; 3、sleep()是线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,不再次获得对象锁才会进入运行状态; public class MultiThread { private static class Thread1 implements Runnable{ @Override public void run() { //由于 Thread1和下面Thread2内部run方法要用同一对象作为监视器,如果用this则Thread1和Threa2的this不是同一对象 //所以用MultiThread.class这个字节码对象,当前虚拟机里引用这个变量时指向的都是同一个对象 synchronized(MultiThread.class){ System.out.println("enter thread1 ..."); System.out.println("thread1 is waiting"); try{ //释放锁有两种方式:(1)程序自然离开监视器的范围,即离开synchronized关键字管辖的代码范围 //(2)在synchronized关键字管辖的代码内部调用监视器对象的wait()方法。这里使用wait方法 MultiThread.class.wait(); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("thread1 is going on ..."); System.out.println("thread1 is being over!"); } } } private static class Thread2 implements Runnable{ @Override public void run() { //notify方法并不释放锁,即使thread2调用了下面的sleep方法休息10ms,但thread1仍然不会执行 //因为thread2没有释放锁,所以Thread1得不到锁而无法执行 synchronized(MultiThread.class){ System.out.println("enter thread2 ..."); System.out.println("thread2 notify other thread can release wait status ..."); MultiThread.class.notify(); System.out.println("thread2 is sleeping ten millisecond ..."); try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("thread2 is going on ..."); System.out.println("thread2 is being over!"); } } } public static void main(String[] args) { new Thread(new Thread1()).start(); try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } new Thread(new Thread2()).start(); } } Q: 谈谈你对面向过程,面向对象,面向切面的理解 面向过程(Procedure Oriented)是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装、继承、类。 面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP 达到了软件工程的三个主要目标:重用性、灵活性和扩展性。为了实现整体运算,每个对象都能够接收信息、处理数据和向其它对象发送信息。 面向切面编程(Aspect Oriented Programming(AOP)),是一个比较热门的话题。AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。 切面,指的是项目模块中某些业务逻辑。面向切面编程通俗一点就是面向业务的一种编程思想(当然业务需要一定的共性),然后通过代理完成类的创建,极大程度的降低代码的重复,有效的提高了代码的重用率和开发效率。。。当然结合IOC(控制反转),将对象直接注入到代理类中,通过代理完成调用方法,那就更完美了 切面是横跨流程的,实现某个特定位置的功能,面向功能进行抽象。具体流程只需做引用即可,而不至于不同流程中冗余很多类似代码。

优秀的个人博客,低调大师

android view 转Bitmap 生成截图

文章链接:https://mp.weixin.qq.com/s/FQmYfT-KYiDbp-0HzK_Hpw 项目中经常会用到分享的功能,有分享链接也有分享图片,其中分享图片有的需要移动端对屏幕内容进行截取分享,说白了就是将view 转成bitmap 再到图片分享,还有一种情况是将不可见的view 转成bitmap ,这种view是没有直接显示在界面上的,需要我们使用inflate 进行创建的view。 第一种 先看通过 DrawingCache 方法来截取普通的view,获取它的视图(Bitmap)。 private Bitmap createBitmap(View view) { view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); return bitmap; } 这个方法适用于view 已经显示在界面上了,可以获得view 的宽高实际大小,进而通过DrawingCache 保存为bitmap。 第二种 但是 如果要截取的view 没有在屏幕上显示完全的,例如要截取的是超过一屏的 scrollview ,通过上面这个方法是获取不到bitmap的,需要使用下面方法,传的view 是scrollview 的子view(LinearLayout)等, 当然完全显示的view(第一种情况的view) 也可以使用这个方法截取。 public Bitmap createBitmap2(View v) { Bitmap bmp = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bmp); c.drawColor(Color.WHITE); v.draw(c); return bmp; } 第三种 还有一种 是view完全没有显示在界面上,通过inflate 转化的view,这时候通过 DrawingCache 是获取不到bitmap 的,也拿不到view 的宽高,以上两种方法都是不可行的。第三种方法通过measure、layout 去获得view 的实际尺寸。 public Bitmap createBitmap3(View v, int width, int height) { //测量使得view指定大小 int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY); int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); v.measure(measuredWidth, measuredHeight); //调用layout方法布局后,可以得到view的尺寸大小 v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); Bitmap bmp = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bmp); c.drawColor(Color.WHITE); v.draw(c); return bmp; } View view = LayoutInflater.from(this).inflate(R.layout.view_inflate, null, false); //这里传值屏幕宽高,得到的视图即全屏大小 createBitmap3(view, getScreenWidth(), getScreenHeight()); 另外写了个简易的保存图片的方法,方便查看效果的。 private void saveBitmap(Bitmap bitmap) { FileOutputStream fos; try { File root = Environment.getExternalStorageDirectory(); File file = new File(root, "test.png"); fos = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } github地址:https://github.com/taixiang/view2bitmap 欢迎关注我的博客:https://www.manjiexiang.cn/ 更多精彩欢迎关注微信号:春风十里不如认识你 一起学习 一起进步

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册