android学习的java,android学习之java常识
1、类的加载执行顺序
publicclassDerviedextendsBase {
privateString name ="dervied";
publicDervied() {
tellName();
printName();
}
publicvoidtellName() {
System.out.println("Dervied tell name: "+ name);
}
publicvoidprintName() {
System.out.println("Dervied print name: "+ name);
}
publicstaticvoidmain(String[] args){
newDervied();
}
}
classBase {
privateString name ="base";
publicBase() {
tellName();
printName();
}
publicvoidtellName() {
System.out.println("Base tell name: "+ name);
}
publicvoidprintName() {
System.out.println("Base print name: "+ name);
}
}
先初始化父类然后再初始化子类(这个初始化包括静态和非静态变量、静态和非静态的方法块、构造函数)
Dervied tell name: null
Dervied print name: null
Dervied tell name: dervied
Dervied print name: dervied
再看一下如下的例子:
classParentClass {
publicstaticinta=2;
publicintb=3;
{
System.out.println("this is anonymity b="+b);
}
static{
a=4;
System.out.println("this is static and a="+a);
}
publicParentClass() {
System.out.println("this is parent gozao");
this.s();
}
publicvoids() {
System.out.println("this is parent");
}
}
publicclassSonextendsParentClass {
publicSon(){
System.out.println("this is son gozao");
}
publicstaticvoidmain(String[] args) {
ParentClass d = newSon();
d.s();
}
publicvoids() {
//super.s();
System.out.println("this is son");
}
}
运行结果如下:
thisisstaticand a=4
thisis anonymity b=3
thisis parent gozao
thisis son
thisis son gozao
thisis son
可以看出类内的加载顺序为:
(1)
静态变量对于静态变量肯定要首先进行初始化,因为后面的方法可能会使用这个变量,或者构造函数中也可能用到。而对于非静态变量而言,由于匿名块内、非静态方法和构造函数都可以进行操作(不仅仅是初始化),所以要提前进行加载和赋默认值。
静态代码块 多个静态代码块按顺序加载,这里需要注意:在这个顺序不难是类内书写的顺序,也是类加载的顺序,也就是说如果子类也有静态代码块,则子类的也加载。由于静态代码块可能会负责变量的初始化,或者是对象等的初始化,这样在构造函数或者方法中就变得可用了。而顺序加载多半是由于Java是按顺序执行代码的原因。
静态方法一般静态方法中禁止引用还未初始化的非静态变量,如果引用了静态变量,则静态变量必须放到这个静态方法的前面,以保证在使用时已经被正确地初始化。
一般如上要按顺序执行加载。
如果静态代码块中用到了静态变量,则静态变量必须在前面,如果在后会出现编译错误,而静态代码块中不可以出现非静态的变量。
publicstaticinta=2;// 必须放到静态代码块前
// public int a=3; // 代码块中会报错
{
System.out.println("this is anonymity b="+b);
}
static{
System.out.println("this is static and a="+a);
} 静态方法与静态变量的关系和上面一样。
(2)
匿名代码块这个要后初始化于静态代码块和静态变量,因为其依然属于实例对象,而不属于类。在这里可以对非静态成员变量进行初始化工作,同样也可以引用静态变量,因为已经被初始化过了。
非静态变量这个要后初始化于静态代码块和静态变量,如果在匿名代码块中有对非静态变量的引用,则非静态变量必须在前面,以保证先被初始化。对静态变量的位置不做要求。举例:
publicintb=3;// 必须放到匿名代码块的前面,以保证先被初始化后使用
{
System.out.println("this is anonymity b="+b);
}
publicstaticintb=2;// 可以放到匿名代码块的任意位置
如果两者没有引用,则按顺序执行加载。
(3)
构造函数 这里需要解释一下,为什么初始化子类必先初始化父类,由于子类可能会继承父类的属性或方法,所以肯定要先初始化父类了,而初始化父类则必须要调用父类的构造函数。
至于方法不用考虑,因为方法不用初始化,所以无论是静态还是不静态,和这个没有关系。
其实如上的代码还能说明一些问题,可以看到,在父类中通过this.s()调用的是子类的方法,子类的s()方法覆盖了父类的方法后,无论在哪里调用,都是调用子类的方法。
下面再来看一个比较复杂的面试题(阿里巴巴),如下:
publicclassInitializeDemo {
privatestaticintk =1;
privatestaticInitializeDemo t1 =newInitializeDemo("t1");
privatestaticInitializeDemo t2 =newInitializeDemo("t2");
privatestaticinti = print("i");
privatestaticintn =99;
static{
print("静态块");
}
privateintj = print("j");
{
print("构造块");
}
publicInitializeDemo(String str) {
System.out.println((k++) + ":"+ str +" i="+ i +" n="+ n);
++i;
++n;
}
publicstaticintprint(String str) {
System.out.println((k++) + ":"+ str +" i="+ i +" n="+ n);
++n;
return++i;
}
publicstaticvoidmain(String args[]) {
newInitializeDemo("init");
}
} 最终的输出结果如下:
1:j i=0n=0
2:构造块 i=1n=1
3:t1 i=2n=2
4:j i=3n=3
5:构造块 i=4n=4
6:t2 i=5n=5
7:i i=6n=6
8:静态块 i=7n=99
9:j i=8n=100
10:构造块 i=9n=101
11:init i=10n=102 对其进行解释如下:
1. 运行main方法的时候,JVM会调用ClassLoader来加载Test类,那么一起源于这次加载
2. 上面有四个静态属性,所以会按顺序逐一初始化这四个静态属性
3.privatestaticintk =1; 此时将k初始化为1
4.privatestaticTest t1 =newTest("t1"); 创建Test对象,那么按照核心理念中的顺序
先执行 privateintj = print("j"); 打印出j,然后执行构造块,最后执行构造方法
5.privatestaticTest t2 =newTest("t2"); 同步骤4
6.privatestaticinti = print("i"); 打印i
7.privatestaticintn =99; 直到这一步,n才被赋值为99,之前是从默认的0开始++的
8. 静态属性初始化完毕,代码走到静态块,打印出静态块,此时n=99
9. 静态属性和静态块执行完毕,然后执行main方法中的代码newTest("init");
10.main方法中创建对象,先初始化非静态属性,privateintj = print("j");打印j,然后执行构造块,最后执行构造方法
2、不可变类
不可变类是指当创建了这个类的实例后,就不允许修改它的属性值。在JDK的基本类库中,所有基本类型的包装类,如Integer、Long等都是不可变类,除此之外还有java.lang.String也是不可变类。
不可变类的实例一但创建,其内在成员变量的值就不能被修改。创建一个不可变类需要如下条件:
对于一般成员都是private,还可以使用public static final 来定义一个全局的常量。
不提供对成员的修改方法,例如:setXxx()
确保所有的方法不会被重载。手段有两种:使用final Class(强不可变类),或者将所有的类方法加上final关键字(弱不可变类)。
如果某一个类成员不是原始变量(primitive)或者不可变类,必须通过在成员初始化或者get方法时通过深度clone方法,来确保类的不可变。
其它的都好理解,下面来着重解释一下第4条。举个例子:
publicfinalclassMyImmutableWrong {// 使用final关键字声明为强不可变类
privatefinalint[] myArray;
publicMyImmutableWrong(int[] anArray) {
this.myArray = anArray;// wrong
}
publicString toString() {
StringBuffer sb = newStringBuffer("Numbers are: ");
for(inti = 0; i
sb.append(myArray[i] + " ");
}
returnsb.toString();
}
} 由于int[] anArray是一个数组,属于引用类型。这样当再次去操作外部的一个引用时,其指向的共同内容,也就是数组的值。
publicclassdd {
publicstaticvoidmain(String[] args) {
intarray[]={1,2,3,4};
MyImmutableWrong service=newMyImmutableWrong(array);
array[2]=99;
System.out.println(service.toString());
}
} 查看控制台的输出内容:
Numbers are: 1 2 99 4
可以看到,不可变类中的数组内容发生了改变。究其原因就是 - 关键字final仅对其直接指向的对象有用,并且final引用可以指向带有非final域的对象。
为了避免这个问题,必须对数组进行深度克隆。也就是专门再为不可变类中的数组开避一份内存空间,然后将参数的值赋值过去。
正确的写法如下:
publicfinalclassMyImmutableCorrect {
privatefinalint[] myArray;
publicMyImmutableCorrect(int[] anArray) {
this.myArray = anArray.clone();
}
publicString toString() {
StringBuffer sb = newStringBuffer("Numbers are: ");
for(inti =0; i
sb.append(myArray[i] + " ");
}
returnsb.toString();
}
} 测试后发现:
Numbers are: 1 2 3 4
不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。
3、静态内部类
内部类就是在一个类的内部定义的类,内部类中不能定义静态成员(静态成员不是对象的特性,只是为了找一个容身之处,所以需要放到一个类中而已,把“全局变量”放在内部类中就是毫无意义的事情,所以被禁止),内部类可以直接访问外部类中的成员变量,即使这个成员变量是由private来修饰的。
同样拿不可变类来举一个例子。假如这个不可变类中有许多的private final属性需要初始化,这时候看起来就不太方便。可能有人会采用工厂方法来解决,但有时候也可以使用静态内部类来解决这一问题。如下:
publicclassAuthor {
privatefinalString name;
publicString getName() {
returnname;
}
publicAuthor(String name_) {
name = name_;
}
@Override
publicString toString() {
return"Author [name="+ name +"]";
}
}
publicfinalclassUpdate {// 强不可变类
privatefinalAuthor author;// 作者,是个引用变量
privatefinalString updateText;// 更新内容
privatefinallongcreateTime;// 更新时间
// 私有构造函数,防止外部实例化
privateUpdate(Builder b_) {
author = b_.author;
updateText = b_.updateText;
createTime = b_.createTime;
}
// 构建器
publicstaticclassBuilder {
privatelongcreateTime;
privateAuthor author;
privateString updateText;
publicBuilder author(Author author_) {
author = author_;
returnthis;
}
publicBuilder updateText(String updateText_) {
updateText = updateText_;
returnthis;
}
publicBuilder createTime(longcreateTime_) {
createTime = createTime_;
returnthis;
}
publicUpdate build() {// 更新外部类的值
returnnewUpdate(this);
}
}
publicAuthor getAuthor() {
returnauthor;
}
publicString getUpdateText() {
returnupdateText;
}
@Override
publicString toString() {
return"Update [author="+ author +", updateText="+ updateText
+ ", createTime="+ createTime +"]";
}
} 可以看到,静态内部类有与外部类同样的成员变量,但是静态内部类中的成员变量却是可以修改的。
来测试一下:
publicclassTest {
publicstaticvoidmain(String[] args) {
finalUpdate first = getUpdate("abc");// 获取不可变类的实例
System.out.println(first.toString());
}
privatestaticUpdate getUpdate(String s) {
Update.Builder b = newUpdate.Builder();
b.updateText(s).author(newAuthor("mazhi"));
returnb.build();// 初始化不可变类并返回实例
}
} 运行后的结果如下:
Update [author=Author [name=mazhi], updateText=abc, createTime=0]
在方法外部定义的内部类可以加上static关键字、可以定义成public、protected、默认的、private等多种类型,而普通类只能定义成public和默认的这两种类型。在外面引用静态内部类的名称为"外部类名.内部类名"。不需要创建外部类的实例对象,就可以直接创建静态内部类。例如:
Update.Builder b =newUpdate.Builder();// 获取静态内部类的实例对象
由于不依赖于外部类的实例对象,所以能访问外部类的非static成员变量。
想了解更多的内部类,可以查阅其它资料。
来看一道笔试题目,如下
/**
* 不用比较运算符,判断int型的a,b两数的大小.
*/
public class Compare {
public static void main(String[] args) {
int a=30;
int b=2;
String[] buf= { "a>=b", "a
int id1= (a - b)>>31;
System.out.println(id1); // 1
System.out.println(buf[id1]); // a
}
}
要想顺利解答,需要掌握Java中一些最基础的运行符
4、移位运算符
Java中有三种移位运算符:
<>(右移运算符)、>>>(无符号右移运算符)
在使用移位运算符时要注意:
1、只适用于byte、short、char、int、long类型运算
2、低于int类型的操作数会自动转换为int类型进行移位
3、如上的移位运算符的右边永远是移动的位数
举例:
/*
* 12的2进制代码为1100,由于整数类型只有32位,所以如果移动的位数大于32,则与32位取余,也就是如果移动位数为35,则35%32=3,移动三位即可。而对于long类型来说,会与64位进行取余运算
* */
System.out.println(12>>33);//6
System.out.println(12>>32);//12
5、扩展运算符
需要好好掌握的就是赋值运算符(+=)
a=a+5与a+=5在底层的运行机制还是存在一定的差异性的。如果a为byte类型,则a=a+5会出错,而后者就不会。由于a为byte类型时,当a=a+5时,等号右边a+5会转换为int类型,在赋值byte类型(a),当然会报错。如下:
bytea=3;
a+=5;// 会自动将int类型转换为byte
a=a+5;// 需要进行强制类型转换,因为a+5为int型,赋值byte会出错
6、与、或、非运算符
& 和 && 的区别
1、&和&&都可以用作逻辑与的运算符,表示逻辑与(and)。
2、&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式。
举例:
if(str !=null&& !str.equals("")){
// ...
} 表达式,当str为null时,后面的表达式不会执行,所以不会抛出异常NullPointerException。如果将&&改为&,则会抛出NullPointerException异常。再举例如:
If(x==33& ++y>0){ ... }// y会增长
If(x==33&& ++y>0){ ... }// y不会增长
3、&还用作 位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01
4、&在C语言中也可作为一元运算符,返回操作数的地址。
归纳为逻辑操作(&,|,^)与条件操作(&&,||)之间的区别:
a.条件操作只能操作布尔型,而逻辑操作不仅可以操作布尔型,而且可以操作数值型,如取一个整的特定位数
b.逻辑操作不会产生短路
4、三元表达式(?:)
charx ='X';
inti =0;
System.out.println(true? x :0);// X
System.out.println(false? i : x);// 88
条件表达式结果类型的规则:
(1) 如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类型。
(2) 如果一个操作的类型是T,T表示byte、short或char,而另一个操作数是一个int类型的“字面常量”,并且
它的值可以用类型T表示,那条件表达式的类型就是T。
(3) 否则,将对操作数类型进行提升,而条件表达式的类型就是第二个和第三个操作被提升之后的类型。
现来使用以上规则解上面的迷题,第一个表达式符合第二条规则:一个操作数的类型是char,另一个的类型是字面常
量为0的int型,但0可以表示成char,所以最终返回类型以char类型为准;第二个表达式符合第三条规则:因为i为int
型变量,而x又为char型变量,所以会先将x提升至int型,所以最后的结果类型为int型,但如果将i定义成final时,
则返回结果类型为char,则此时符合第二条规则,因为final类型的变量在编译时就使用“字面常量0”来替换三元表
达式了:
finalinti =0;
System.out.println(false? i : x);// X
在JDK1.4版本或之前,条件操作符 ?: 中,当第二个和延续三个操作数是引用类型时,条件操作符要求它们其中一个
必须是另一个的子类型,那怕它们有同一个父类也不行:
publicclassT {
publicstaticvoidmain(String[] args) {
System.out.println(f());
}
publicstaticT f() {
// !!1.4不能编译,但1.5可以
// !!return true?new T1():new T2();
returntrue? (T)newT1() :newT2();// T1
}
}
classT1extendsT {
publicString toString() {
return"T1";
}
}
classT2extendsT {
publicString toString() {
return"T2";
}
}
在5.0或以上版本中,条件操作符在延续二个和第三个操作数是引用类型时总是合法的。其结果类型是这两种类型的最
小公共超类。公共超类总是存在的,因为Object是每一个对象类型的超类型,上面的最小公共超类是T,所以能编译。
7、final关键字
1.1 final关键字的使用
(1)修饰类 如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能同时声明为abstract final或者interface final的。
(2)修饰方法 将方法声明为final,可以保证它们在使用中不被改变。被声明为final的方法也同样只能使用,不能重载。但是子类可以继承父类的final方法。
(3)修饰变量 表示属性值第一次初始化后不能被修改。final属性可以直接初始化或在构造函数中初始化 如果属性是直接初始化,则其值不能被其它函数(包括构造函数)修改。
publicfinalinta=2;
publicBaseType(){// 构造方法
a=3;// 编译报错
}
(4)修饰方法参数 参数值不能被修改 (5)修饰方法中的局部变量 局部变量被第一次初始化后不能被修改
publicvoidhello() {
finalString name;
name = "hi";// ok
name = "hello";// error
}
1.2 常见final的错误应用
classSomething {
finalinti;
publicvoiddoSomething() {
System.out.println("i = "+ i);
}
}
final int i是个final的实例变量。final的实例变量没有默认值,必须在constructor(构造器)结束之前被赋予一个明确的值。可以修改为"final int i = 0;" 再举一个例子:
interfacePlayable {
voidplay();
}
interfaceBounceable {
voidplay();
}
interfaceRollableextendsPlayable, Bounceable {
Ball ball = newBall("PingPang");// 默认为public static final类型的
}
classBallimplementsRollable {
privateString name;
publicString getName() {
returnname;
}
publicBall(String name) {
this.name = name;
}
publicvoidplay() {
ball = newBall("Football");
System.out.println(ball.getName());
}
} 任何在interface里声明的成员变量,默认为public static final。
Ball ball =newBall("PingPang");// 等价于 public static final Ball ball = new Ball("PingPang");
在Ball类的Play()方法中,改变了ball的引用,而这里的ball来自Rollable interface,因此编译器将在"ball = new Ball("Football");"这里显示有错。
从如上的两个例子可以看出,final使得被修饰的变量”不变”,但是由于对象型变量的本质是”引用”,使得”不变”也有了两种含义:引用本身的不变和引用指向的对象不变。
finalStringBuffer a=newStringBuffer("immutable");
finalStringBuffer b=newStringBuffer("not immutable");
//a=b; // 编译期错误
a.append(" xx");// 改变引用的内容
System.out.println(a); // 结果为:immutable xx 当a=b时会出现编译错误,不允许改变引用,但是我们却可以改变其引用的内容,如a.append(" xx");就改变了其引用指向的内容。所以经常有人会范如下的错误:
publicclassSomething {
publicstaticvoidmain(String[] args) {
Other o = newOther();
newSomething().addOne(o);
}
publicvoidaddOne(finalOther o) {
o.i++;
}
}
classOther {
publicinti;
}
想通过添加final字段来阻止Other类中i的改变,其实这是办不到的,如上的程序依然能够通过o.i++来改变i的值。
1.3 使用final的意义
第一,为方法“上锁”,防止任何继承类改变它的本来含义和实现。设计程序时,若希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写,就可以采取这种做法。
第二,提高程序执行的效率,将一个方法设成final后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里(内嵌机制)。
1.4 Java7新特性 - final重抛
在Java7以前,经常可以看到如下的代码片段:
try{
inta=0,x;
x=3/a;
}catch(Exception e){
throwe;
} 如上会将新抛出的异常类型java.lang.ArithmeticException声明为Exception,而真实具体的确被覆盖了。使用Java7新语法:
try{
inta=0,x;
x=3/a;
}catch(finalException e){
throwe;
}
只需要加个final关键字字即可,这样就不会抛出笼统的异常类型,这叫“final重抛‘。
8、finally关键字
再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块。 所以说finally块是一定会被执行的。
finally 语句块是在 try 或者 catch 中的 return 语句之前执行的。更加一般的说法是,finally 语句块应该是在控制转移语句之前执行,
控制转移语句除了 return 外,还有 break 和 continue。
另外,throw 语句也属于控制转移语句。虽然 return、throw、break 和 continue 都是控制转移语句,但是它们之间是有区别的。其中 return 和 throw 把程序控制权转交给它们的调用者(invoker),而 break 和 continue 的控制权是在当前方法内转移。
publicclassTest {
publicstaticvoidmain(String[] args) {
System.out.println("return value of getValue(): "+ getValue());
}
publicstaticintgetValue() {
try{
return0;
} finally{
return1;
}
}
} 执行结果为:return value of getValue(): 1。因为finally 语句块是在 try 或者 catch 中的 return 语句之前执行的。
publicclassTest {
publicstaticvoidmain(String[] args) {
System.out.println("return value of getValue(): "+ getValue());
}
publicstaticintgetValue() {
inti =1;
try{
returni;
} finally{
i++;
}
}
}
其执行结果为:
return value of getValue(): 1
究其原因,我们来分析一下其执行顺序:分为正常执行(没有 exception)和异常执行(有 exception)两种情况。我们先来看一下正常执行的情况。打开.class文件,代码如下:
publicstaticintgetValue();
0iconst_1
1istore_0 [i]
2iload_0 [i]
3istore_2
4iinc01[i]
7iload_2
8ireturn
9astore_1
10iinc01[i]
13aload_1
14athrow
Exception Table:
[pc: 2, pc:4] ->9when : any
Line numbers:
[pc: 0, line:9]
[pc: 2, line:11]
[pc: 4, line:13]
[pc: 7, line:11]
[pc: 9, line:12]
[pc: 10, line:13]
[pc: 13, line:14]
Local variable table:
[pc: 2, pc:15] local: i index:0type:int
Stack map table: number of frames 1
[pc: 9, full, stack: {java.lang.Throwable}, locals: {int}]
} 其执行图如下所示。
可以看到,如上的结果为什么是1而不是2了。 继续来看下一道题:
publicclassTest {
publicstaticvoidmain(String[] args) {
System.out.println(test());
}
publicstaticString test() {
try{
System.out.println("try block");
returntest1();// 相当于代码String tmp=test1();return temp;
} finally{
System.out.println("finally block");
}
}
publicstaticString test1() {
System.out.println("return statement");
return"after return";
}
}
运行结果为:
try block return statement finally block after return
其实finally在项目开发中的主要作用就是关闭资源,如数据库连接对象Connection、输入流/输出流等。在JDK7中对此做了改变。把资源的作用域限定在代码块内,当程序离开这个代码块时,资源会被自动关闭,这就防止了未关闭而造成资源浪费等一些问题。
资源在处理完毕后,会自动关闭br。
9、finalize 方法名
Java 技术允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
android学习的java,android学习之java常识相关推荐
- java/android 设计模式学习笔记(1)--- 单例模式
前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...
- 给Android工程师的Java后台学习建议
给Android工程师的Java后台学习建议 作为一个原生Android开发,一路走来经历了Java . Kotlin的洗礼:在"原生要凉"的氛围下学习Cordova.ReactN ...
- Java Android、IOS、前端、数据库、C++、Unity3D、Python学习资料
百度云盘资源永久分享,包括计算机中Java & Android.IOS.前端.数据库.C++.Unity3D.Python方面的视频等教学资源. PS:转载的别人的,我只是用来插个眼,感谢大佬 ...
- Android(java)学习笔记176: 远程服务的应用场景(移动支付案例)
一. 移动支付: 用户需要在移动终端提交账号.密码以及金额等数据 到 远端服务器.然后远端服务器匹配这些信息,进行逻辑判断,进而完成交易,返回交易成功或失败的信息给移动终端.用户提交账号. ...
- java/android 设计模式学习笔记目录
其实很早就想开始总结设计模式了,无奈刚刚换完工作,工作太忙,平时周末也太懒,难得提起精神写一点,估计时间会花的很长,不过还是自己加油吧~~. 学习笔记,顾名思义,其实就是我在平时看书,工作的笔记而已, ...
- java/android 设计模式学习笔记(6)---适配器模式
这篇来介绍一下适配器模式(Adapter Pattern),适配器模式在开发中使用的频率也是很高的,像 ListView 和 RecyclerView 的 Adapter 等都是使用的适配器模式.在我 ...
- java/android 设计模式学习笔记(8)---桥接模式
这篇博客我们来介绍一下桥接模式(Bridge Pattern),它也是结构型设计模式之一.桥接,顾名思义,就是用来连接两个部分,使得两个部分可以互相通讯或者使用,桥接模式的作用就是为被分离了的抽象部分 ...
- java/android 设计模式学习笔记(1)---单例模式
前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...
- java/android 设计模式学习笔记(3)---工厂方法模式
这篇来介绍一下工厂方法模式(Factory Method Pattern),在实际开发过程中我们都习惯于直接使用 new 关键字用来创建一个对象,可是有时候对象的创造需要一系列的步骤:你可能需要计算或 ...
- java/android 设计模式学习笔记(7)---装饰者模式
这篇将会介绍装饰者模式(Decorator Pattern),装饰者模式也称为包装模式(Wrapper Pattern),结构型模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时它也是 ...
最新文章
- 字体中字号,磅值和mm之间的转换
- 去除JSP页面中JSTL、EL生成的空行
- [BUUCTF-pwn]——picoctf_2018_shellcode
- 电子工程师,学会阅读Datasheet很重要!
- 拼接图像亮度均匀调整_品质不变 价格更香 | 爆款拼接屏新品上市
- 重大调整!余承东兼任华为云与计算 BG 总裁
- cemtos7重置mysql root,Centos7重置MySQL8.0 root密码
- linux write函数_韦东山:6000字长文告诉你如何学习嵌入式linux
- UITextView使用与YYlabel使用比较
- 小米机器如何无root激活XPOSED框架的流程
- opencv学习(四十四)之图像角点检测Harris
- 参加了feedsky的blog挑战赛
- Congestion 问题怎么解决?
- H5网页元素和全局属性
- 【科研】论文得分低、濒临被拒不要慌,18条rebuttal小贴士助你说服评审和AC
- vue-video-play 记载视频观看时间和还原视频进度
- 【研一周小结】第二周个人学习总结
- 高精度电子罗盘的应用场景
- 如何对MES解决方案进行需求分析
- python银行ATM自动取款机
热门文章
- 为什么要用shiro框架_社群裂变为什么要用微信群助手?怎么去策划社群的线上裂变?...
- servlet中文乱码_Servlet入门 信息过滤
- docker 镜像修改的配置文件自动还原_所以到底该如何修改 docker 容器的端口映射!!!...
- 协同过滤算法_基于用户的协同过滤推荐算法原理和实现
- 万能套用PS分层模板,不怕老板捉急!
- APP界面设计的视觉思维!
- 优质淘宝产品描述页模板框架PSD分层模板,美工实用素材
- gp3688写频线制作_摩托罗拉GP3688写频软件
- SU编程和Madagascar编程中的函数对比和区别--终端提示函数
- Zlib压缩算法:LZ77、LZ78、霍夫曼编码、滑动窗口、Rabin-Karp算法、哈希链、I/O缓冲区