GithubHelp home page GithubHelp logo

blog's People

Watchers

 avatar  avatar

blog's Issues

Java笔记

  1. Java 语言把内存分为 2 种:栈内存、堆内存。

    • 栈内存:方法中定义的基本类型变量和对象的引用变量都在方法的栈内存中。当在一段代码块中定义一个变量时,Java 就在栈内存中为其分配内存空间,当超出变量的作用域后,Java 会自动释放掉为该变量所分配的内存空间。
    • 堆内存:存放由 new 运算符创建的对象和数组。在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中创建了一个数组或对象后,同时还会在栈中定义一个引用变量,保存其在堆内存中的地址(对象的句柄)。以后可以在程序中使用栈的引用变量来访问堆中的数组或对象。

    引用变量是普通变量,定义时在栈中分配,程序运行到其作用域之外后被释放。
    数组或对象本身在堆内存中分配,即使程序运行到使用 new 运算符创建的语句所在的代码块之外,其本身所占的内存也不会被释放,在没有引用变量指向它时,会变为垃圾,不能再被使用,但仍占据内存空间,在随后一个不确定的时间被垃圾回收器收走(释放掉),这也是 Java 比较占内存的原因。

  2. Java 语言的多维数组不一定是规则的矩阵形式,即每行的元素个数可以不同。用 new 运算符为数组申请内存空间时,二维数组必须指定高层维数。

  3. String 类创建的字符串变量,一旦初始化或赋值,它的值和所分配的内存内容就不可再改变。如果改变其值,就会产生一个新的字符串

  4. 修饰符。
    一个可以有多个修饰符,且无先后顺序之分,但 abstract 和 final 相互对立,不能同时应用在一个类的定义中。
    同一个 Java 程序内,若定义了多个类,则最多只能有一个类声明为 public,此时文件名必须与声明成 public 的类名称相同。

    类修饰符 含义
    public 声明为公共类,可以被任何对象访问
    abstract 抽象类,没有实现方法,需要子类提供方法的实现,不能创建该类的实例
    final 最终类(非继承类),不能被其他类继承
    缺省 只有在相同包中的对象才能使用该类
    成员变量修饰符 含义
    public 公共访问控制符,可以被任何对象的方法访问
    private 私有访问控制符,只允许自己类的方法访问
    protected 保护访问控制符,只可以被自己的类及其子类或同一包中的其他类访问,在子类中可以覆盖此变量
    缺省 缺省访问控制符,可以被同一个包中的其他类访问
    final 最终修饰符,称为最终变量,此变量的值不能被改变
    static 静态修饰符,该变量被所有对象共享,即所有实例都可使用该变量
    transient 过渡修饰符,系统保留、暂无特别作用的临时性变量
    volatile 易失修饰符,可以同时被几个线程控制和修改

    一个成员变量若被 static final 同时限定,则其含义即是常量,只能在定义时被赋值。
    若只用final,则必须且只能赋值一次,不能缺省。赋值方式有 2 种:定义变量时;构造方法中。

    成员方法修饰符 含义
    public 公共访问控制符,可以被何对象的方法访问
    private 私有访问控制符,只允许自己类的方法访问,不能被继承和覆盖
    protected 保护访问控制符,只可以被自己的类及其子类或同一包中的其他类访问,在子类中可以覆盖此变量
    缺省 缺省访问控制符,可以被同一个包中的其他类访问
    final 最终修饰符,该方法称为最终方法,不能被重载。(对于一些比较重要且不希望被子类重写的方法,使用 final 可增加代码的安全性)
    static 静态修饰符,无需实例化一个对象就可以调用该方法,不能被重载
    abstract 抽象修饰符,只声明方法头,没有方法体,需在子类中实现
    synchronized 同步修饰符,在多线程程序中,该修饰符用于在运行前,对它所属的方法加锁,以防止其他线程访问,运行结束后解锁
    native 本地修饰符,方法体是用其他语言在程序外部编写的
  5. 成员变量与局部变量的区别

    区别 成员变量 局部变量
    定义 类中定义 方法中定义
    修饰符 不能被访问控制符及 static 修饰
    内存中的存储方式 堆内存(成员变量是对象的一部分,对象存在堆内存) 栈内存
    内存中的生存时间 随着对象的创建而存在 随着方法的调用而产生,方法调用的结束而自动消失
    未赋初值的默认值 类型的默认值(例外:final 修饰但没被 static 修饰,必须显式赋值) 必须显式赋值
  6. 创建对象
    对象是类的实例,故对象属于某个已知的类。
    创建对象的步骤:
    (1)声明指向“由类所创建的对象”的变量。 Book book;
    以类名 Book 作为变量类型在栈内存中定义了一个变量 book,用来指向通过 new 运算符在堆内存中创建的一个 Book 类的实例对象,即 变量 book 是对存放在堆内存中对象的引用变量。
    因 book 变量是指向由 Book 类所创建的对象,可将它视为“对象的名称”,简称“对象”,事实上,book 只是对象的名称,是指向对象实体的变量,而非对象本身。
    (2)利用 new 运算符创建新的对象,并指派给前面所创建的变量。 book = new Book();

  7. 除了基本类型之外的变量都是引用类型。

    成员变量类型 初始值
    byte 0
    short 0
    int 0
    long 0L
    float 0.0F
    double 0.0D
    char '\u0000'(表示为空)
    boolean false
    所有引用类型 null
  8. 在类定义内调用方法。若强调是“对象本身的成员”,则使用this.成员名,此时 this 即代表调用此成员的对象。

  9. 参数的传递
    基本数据类型 —— 传值方式(数据的值本身)
    引用型变量 —— 传址方式(引用变量的值本身。通过方法调用,可以改变对象的内容,但对象的引用变量无法改变)

  10. 匿名对象
    new Book().setName("math");
    当方法执行完后,这个对象也成了垃圾。
    通常在如下 2 种情况使用匿名对象:
    (1)若对一个对象只需要进行一次方法调用
    (2)将匿名对象作为实参传递给一个方法调用。 getSomeone(new MyClass());

  11. “封装”是指把变量和方法包装在一个类中,以限定成员的访问,从而达到保护数据的一种技术。

  12. 实例 —— 类所创建的对象。

  13. 构造方法
    (1)在对象被创建时完成对类对象的初始化工作。
    (2)方法名与所在类名完全相同
    (3)构造方法没有返回值,但在定义构造方法时,构造方法名前不能用修饰符 void 来修饰,因为一个类的构造方法的返回值类型就是该类本身。
    (4)构造方法定义后,创建对象时就会自动调用它,因此构造方法不需要在程序中直接调用,而是在对象产生时自动执行。
    (5)若省略构造方法,Java 编译器会自动为该类生成一个默认的构造方法,程序在创建对象时会自动调用默认的构造方法。默认的构造方法没有参数,方法体也没有代码,即什么都不做。若 class 是public,则默认构造方法也是 public 的。
    (6)一旦用户定义了构造方法,系统就不再提供默认的构造方法。
    (7)从一个构造方法中调用另一个构造方法,使用 this关键字,且必须写在构造方法的第一行。
    (8)构造方法一般是 public 的,因为它们在创建对象时,是在类的外部被系统自动调用的。若是 private,则无法在该类以外被调用。

  14. (1)静态成员:被 static 修饰的成员。
    静态变量(类变量):属于类的变量,而不属于任何一个类的具体对象,是保存在类的内存空间的公共的存储单元中。静态变量必须独立于方法之外。
    静态方法(类方法):属于整个类,故不能操纵和处理属于某个对象的成员,只能处理属于整个类的成员。即 static 方法只能访问 static 成员变量或调用 static 成员方法,在静态方法中不能访问实例变量和实例方法。在静态方法中,不能使用 thissuper,因为 this 代表调用该方法的对象,,但现在静态方法不需要对象来调用,故 this 也自然不应存在于静态方法内部。
    理解public static void main(String[] args){}
    Java 虚拟机需要在类外调用 main() 方法,故该方法的访问权限必须是 public,又因为 Java 虚拟机运行时是系统在开始执行一个程序前,并没有创建 main() 方法所在类的实例对象,故它只能通过类名来调用 main() 方法作为程序的入口,故必须是 static 的。
    (2)实例成员:不被 static 修饰的成员。实例成员属个别对象所有,彼此之间不能共享(new 的不同对象各自拥有自己保存自己成员的存储空间,不与其他对象共享)。

  15. 静态初始化器:由 static 修饰的一对“{ }”括起来的语句组,用来初始化工作。

    static {
    //初始化工作
    }

    和构造方法的区别:

    构造方法 静态初始化器
    对每个新创建的对象初始化 对类自身进行初始化
    在 new 创建新对象时由系统自动执行 一般不能由程序来调用,是在所属的类被加载入内存时由系统调用执行的
    new 创建多少个对象,构造方法就被调用多少次 在类被加载入内存时只执行一次,与创建多少个对象无关(类是在第一次使用时被装载,而不是在程序启动时就装载程序中所有可能要用到的类。
    不是方法,没有方法名、返回值和参数
  16. 继承
    (1)子类的每个对象也是其父类的对象,这是继承性的“即是”性质。若 Sub 继承 Super,则在任何可以使用 Super 实例的地方,都可以使用 Sub 实例,反之则不然,父类对象不一定是它的子类的对象。
    (2)使用 super() 调用父类中特定的构造方法。
    (3)执行子类的构造方法前,若未用 super() 调用父类的特定构造方法,则会先调用父类中的无参构造方法,其目的是为了要帮助继承自父类的成员做初始化操作。(故,若父类中只定义了有参构造方法,而在子类构造方法中没用 super() ,则编译时将发生错误 —— 解决:在父类里加上一个不做事的无参构造方法。)
    (4)构造方法无法继承。
    (5)super()this() 均必须放在构造方法的第一行,故 super()this() 无法同时存在于同一个构造方法内。
    (6)和 this 一样,super 也指的是对象,故 super 同样不能在 static 环境中使用,包括静态方法和静态初始化器。
    (7)super可以访问父类的构造方法、成员变量和成员方法。
    (8)覆盖
    通过父类对象访问子类的成员时,只限于“覆盖”的情况发生时。(声明父类变量 per 指向子类对象 Student,利用父类对象 per 调用子类中覆盖的方法)
    向上转型:创建父类类型的变量指向子类对象,即将子类对象赋值给父类类型的变量。是从一个较具体的类到一个较抽象的类之间的转换,所以是安全的。
    向下转型:将父类对象通过强制转换为子类型再赋值给子类对象。将较抽象的类转换为较具体的类。(Student stu = (Student)per;)必须使用显示转换。

  17. Object 类
    所有类都是直接或间接地继承自 Object 类。若某个类没有使用 extends,则默认为 Object 的子类。
    (1)equals() 方法
    对于字符串的操作,Java 程序在执行时会维护一个字符串池(String Pool),对于一些可共享的字符串对象,会先在 String 池中查找是否有相同的 String 内容(字符相同),若有就直接返回,而不是直接创建一个新的 String 对象,以减少内存的占用。当在程序中使用“"”括起来的一个字符串时,该字符串就会在 String 池中。

    “==”:比较 2 个变量本身的值,即 2 个对象在堆内存中的首地址,即是否指向同一个对象。
    “equals()”:对于字符串 —— 比较 2 个字符串中所包含的内容是否相同。
    对于非字符串类型变量 —— 和“==”一样。
    (2)getClass():返回运行时的对象所属的类(Class 类型)。
    一个 java.lang.Class 对象代表了 Java 应用程序运行时所加载的类或接口的实例,Class 对象由 JVM 自动产生,每当一个类被加载时,JVM 就自动为其生成一个 Class 对象。Class 类没有构造方法,通过 Object 类的 getClass() 来取得对象对应的 Class 对象。
    (3)对象运算符 instanceof:测试指定对象是否是指定类或其子类的实例,是则返回 true。

  18. 抽象类 abstract class
    (1)抽象类不能创建对象,只能由其子类创建对象。专门用作父类。
    (2)抽象方法:只需声明,不需实现,用 “;” 结尾,而不是 “{}”。必须被子类覆盖,否则子类仍是 abstract。
    (3)抽象类不能用 final 修饰。(因为要继承)
    (4)abstract 不能与 private、static、final、native并列修饰同一个方法。
    (5)抽象类不一定包含抽象方法,但包含抽象方法的类一定要申明为抽象类。非抽象类中不能存在抽象方法。
    (6)抽象类可以有构造方法且可被子类的构造方法调用,但构造方法不能声明为抽象的。一般在抽象类定义构造方法是多余的。

  19. 接口 Interface

    [public] interface 接口名 [extends 父接口名列表] {
       [public] [static] [final] 数据类型 成员变量名 = 常量; //若省略,则系统默认为 public static final
       ……
       [public] [abstract] 返回值数据类型 方法名 (参数表); //若省略,则系统默认为 public abstract
    }

    (1)接口的数据成员都是静态的且必须初始化,即必须是静态常量。
    (2)接口的方法必须全部声明为 abstract,即全部是抽象方法。
    (3)接口可以作为一种引用类型来使用,可以声明接口类型的变量或数组,并用它来访问实现该接口的类的对象。
    (4)接口是多重继承:一个接口可以有一个以上的父接口,用逗号分隔,新接口将继承所有父接口中的变量与方法。

  20. 内部类
    (1)内部类可以声明为 private 或 protected
    (2)内部类前面用 final,表明该类不能被继承
    (3)可以为 abstract,但要被其他的内部类继承或实现
    (4)不能与包含它的外部类同名
    (5)内部类既可以使用外部类的成员变量,也可以使用内部类所在方法的局部变量
    (6)内部类也可以是一个接口,该接口必须由另一个内部类来实现。
    (7)既可以在类中定义,也可以在程序块之内定义(方法中或循环体内部等)。方法中定义的内部类只能访问方法中的 final 局部变量。
    (8)内部类若被声明为 static,则静态内部类将自动转化为”顶层类“(top level class),即它没有父类,且不能引用外部类成员或其他内部类中的成员。只有静态内部类才能声明静态成员。

  21. 匿名内部类
    没有类名,在定义类的同时,就生成该类的一个对象,利用它访问类里的成员。

    ( //创建匿名内部类,并执行所定义的方法
       new 类名() { //括号 ”()“ 内不允许有参数
            方法名(参数 1, 参数 2, …, 参数 n) {
                 方法体;
            }
       }
    ).方法名(参数 1, 参数 2, …, 参数 n);
  22. 包的 import:“*” 只能表示本层次的所有类,不包括子层次下的类。

  23. Java 语言的垃圾回收
    在 Java 程序的生命周期中,Java 运行环境提供了一个系统的垃圾回收器线程,负责自动回收那些没有引用与之相连的对象所占用的内存,这种清楚无用对象进行内存回收的过程叫做垃圾回收(Garbage-Collection)。
    当一个对象被创建时,JVM 会为该对象分配一定的内存、调用该对象的构造方法并开始跟踪该对象。当对象停止使用时,JVM 将通过垃圾回收器回收该对象所占用的内存。
    系统中任何对象都有一个引用计数器,一个对象被引用 1 次,该对象的引用计数器就加 1,减少一次引用则计数器就减 1。当一个对象的引用计数器减到 0 时,即不被任何引用类型的变量使用时,说明该对象可以回收。
    垃圾回收器的好处:
    (1)它把程序员从复杂的内存追踪、监测、释放等工作中解放出来。
    (2)它防止了系统内存被非法释放,从而使系统更加稳定。
    特点:
    (1)只有当一个对象不被任何引用类型的变量使用时,它占用的内存才可能被垃圾回收器回收。
    (2)不能通过程序强迫垃圾回收器立即执行。
    回收时间对程序员透明。可以通过 System.gc()Runtime.gc() 方法提示垃圾回收器进行内存回收操作,但无法保证立即执行。
    (3)当垃圾回收器将要释放无用对象占用的内存时,先调用该对象的 finalze() 方法。
    当一个对象将要退出生命周期时,可以通过 finalze() 方法来释放对象所占用的其他相关资源,但是 JVM 有很大的可能不调用对象的 finalze() 方法,因此很难保证使用该方法来释放资源是安全有效的。

  24. 异常处理

    java

    (1)try 块中某条语句执行出现异常时,被启动的异常处理机制就会自动捕获到它,然后流程自动跳过产生异常的语句后面的所有尚未执行的语句,系统直接跳到 catch 块。
    (2)无论 try 程序块是否捕获到异常,或者捕获到的异常是否与 catch 后面括号里的异常相同,最后一定会运行 finally 块。finally 块运行结束后,程序再转到 try-catch-finally 块后的语句继续执行。
    (3)多异常处理:当 try 块抛出一个异常时,程序的流程首先转向第一个 catch 块,并审查当前异常对象可否被这个 catch 块接收(异常对象与 catch 后面小括号中的参数类型匹配,即 catch 所处理的异常类型与生成的异常对象的类型完全一致或是它的祖先类)。若 try 块产生的异常对象被第一个 catch 块接收,则程序的流程将直接跳转到这个 catch 块中,try 块中尚未执行的语句和其他 catch 块将被忽略。若 try 块产生的异常对象与第一个 catch 块不匹配,系统将自动转到第二个,依此类推直到找到一个可以接收该异常对象的 catch 块,即完成流程的跳转。若所有的 catch 块都不能与当前的异常对象匹配,则说明当前方法不能处理这个异常对象,程序流将返回到调用该方法的上层方法,依此类推,若所有方法中都找不到合适的 catch 块,则由 Java 运行系统来处理这个异常对象。此时通常会终止程序的执行,退出 JVM 返回到操作系统,并在标准输出设备上输出相关的异常信息。
    (4)异常对象与 catch 的匹配是按照 catch 的先后排列顺序进行的,故 在处理多异常时应注意认真设计各 catch 的排列顺序。一般,将处理较具体、较常见异常的 catch 放在前面,而可以与多种异常类型相匹配的放在较后位置。若将子类异常的 catch 放在父类异常 catch 的后面,则编译不能通过。
    (5)当 try 中语句抛出一个异常时,其后代码不会被执行,可以通过 finally 语句块来为异常处理提供一个统一出口,通常在 finally 中对一些资源做清理工作,如关闭打开文件等。
    (6)当 catch 中含有 System.exit(0) 语句时,则不执行 finally 块,程序直接终止;当 catch 中含有 return 语句时,则执行完 finally 中的语句后再终止程序。
    (7)catch() 括号内只接收由 Throwable 类的子类所产生的对象,其他类均不接收。

  25. 输入输出

    java

    输入输出流按处理数据的类型分为 2 种:
    (1)字节流(Byte Steam)(也称为 二进制字节流 Binary Byte Steam,位流 Bits Stream)
    每次读写 8 位二进制数,只能将数据以二进制方式读写,不能分解、重组、理解这些数据,故可以使之变换、恢复到原来的有意义的状态。
    很多情况下,数据源或目标中含有非字符数据,例如 Java 编译器产生的字节码文件中含有 Java 虚拟机的指令,这些信息不能被解释成字符,所以必须用字节流来输入输出。
    字节流也可以处理文本文件,但是不能直接操作 Unicode 字符,若文件中有汉字,则可能会出现乱码。因此 Java 不提倡使用字节流读写文本文件。
    (2)字符流(Character Stream)
    每次读写 16 位二进制数,并将其作为一个字符,而不是二进制位来处理。
    字符流的源或目标通常是文本文件。Java 中的字符使用的是 16 位的 Unicode 编码,每个字符占有 2 个字节。
    (3)对象流的关闭最好是放在 finally 块中,此时需要关闭的流对象应在 try 块之前定义;若流对象在 try 中定义,那么关闭流对象的语句可放在 try 块的最后面。

  26. 多线程
    (1)概念

    • 程序 Program
      含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中。是静态的代码。
    • 进程 Process
      程序的一次执行过程,是系统运行程序的基本单位。是动态的。
      系统运行一个程序即是一个进程从创建、运行到消亡的过程。
      每个进程间是独立的,除非利用某些通讯管道来进行通信,或是通过操作系统产生交互作用,否则基本上各进程不知道彼此的存在。
    • 多任务 Multi task
      指在一个系统中可以同时运行多个进程,每个进程都有一段专用的内存区域,即使是多次启动同一段程序产生不同的进程也是如此。
      “同时运行”是指由操作系统将系统资源分配给各个进程,每个进程在 CPU 上交替运行,每个进程占有不同的内存空间,内存消耗很大,这使系统在不同的程序之间切换时开销很大,进程之间的通信速度很慢。
    • 线程 Thread (轻量级进程 light-weight process)
      同类的多个线程共享同一块内存空间和一组系统资源。
      进程属于操作系统的范畴,主要是在同一段时间内,可以同时执行一个以上的程序;
      线程是在同一程序内同时执行一个以上的程序段。

    (2)处于运行状态的线程在下列情况下将让出 CPU 的控制权:

    • 线程运行完毕
    • 有比当前线程优先级更高的线程处于就绪状态
    • 线程主动睡眠一段时间(睡眠时进入阻塞状态,睡眠结束进入就绪状态)
    • 线程在等待某一资源

    (3)阻塞状态是因为某种原因系统不能执行线程的状态,这种状态下即使 CPU 空闲也不能执行线程。
    如下情况可使线程进入阻塞状态:

    • 调用 sleep()yield() 方法
    • 为等待一个条件变量,线程调用 wait() 方法
    • 该线程与另一线程 join() 在一起

    (4)处于消亡状态的线程不具有继续运行的能力。

    导致线程消亡的原因:

    • 正常运行的线程完成了它的全部工作,即执行完了 run() 方法的最后一条语句并退出。
    • 当进程因故停止运行时,该进程中的所有线程将被强行终止。

    当线程处于消亡状态,并且没有该线程对象的引用时,垃圾回收器会从内存中删除该线程对象。

    (5)被同时激活的多个线程将同时执行,使用 Thread 类的 join() 方法可使线程有序执行。当某一线程调用 join() 方法时,其他线程会等到该线程结束后才开始执行。

    (6)若直接使用 Thread() 类,在类中 this 即指当前线程;若使用 Runnable 接口,要在此类中获得当前线程,必须使用 Thread.currentThread() 方法。

    (7)互斥:两个或多个线程不能同时发生,无先后次序的要求。
    同步:两个或多个线程有先后次序的约束。
    共享:线程之间对内存数据的共享。

    (8)同步 Synchronized
    当被 Synchronized 限定的代码段执行完,就自动释放互斥锁。

    • 同步语句
    Synchronized (对象)
        临界代码段
    }   
    • 同步方法
    public synchronized 返回类型 方法名() {
        方法体
    }
    public 返回类型 方法名() {
        synchronized(this) {
           方法体
        }
    }

    ① 在任何时刻,一个对象的互斥锁只能被一个线程所拥有。
    ② 只有当一个线程执行完它所调用对象的所有 synchronized 代码块或方法时,该线程才会释放这个对象的互斥锁。
    ③ 临界代码中的共享变量应定义为 private 型。否则,其他类的方法可能直接访问和操作该共享变量,这样 synchronized 的保护就失去了意义。
    ④ 所有对临界代码**享变量的访问与操作均在 synchronized 代码块中进行。
    ⑤ 通常共享变量都是私有静态变量。
    ⑥ 对于一个 static 型的方法,即类方法,要么整个方法是 synchronized,要么整个方法不是 synchronized。
    ⑦ 若 synchronized 用在类声明中,则表示该类中的所有方法都是 synchronized。

    (9)线程间的通信

    方法 功能
    wait() 若一个正在执行同步代码 synchronized 的线程 A 执行了 wait() 调用(在对象 x 上),该线程暂停执行而进入对象 x 的等待队列,并释放已获得的对象 x 的互斥锁。线程 A 要一直等到其他线程在对象 x 上调用 notify()notifyAll() 方法,才能在重获对象 x 的互斥锁后继续执行(从 wait() 语句后继续执行)
    notify() 唤醒正在等待该对象互斥锁的第一个线程。只能在同步代码块里调用
    notifyAll() 唤醒正在等待该对象互斥锁的所有线程,具有最高优先级的线程首先被唤醒并执行。只能在同步代码块里调用

    (10)当线程的 run() 方法运行结束,则线程进入消亡状态。

  27. 泛型
    (1)定义
    泛型所操作的数据类型被指定为一个参数,这个参数称为类型参数(Type Parameters),其实质是将数据的类型参数化。
    利用泛型类创建的对象称为泛型对象,这个过程也称为泛型实例化。

    格式
    泛型类 [修饰符] class 类名<T>
    泛型接口 [public] interface 接口名<T>
    泛型方法 [public] [static] <T> 返回值类型 方法名(T 参数)

    (2)设计泛型方法的目的主要是针对具有容器类型参数的方法的。若编写的代码并不接受和处理容器类型,就不需要使用泛型方法。

    (3)限制泛型的可用类型

    class ClassName <T extends anyClass>

    anyClass 指某个类或接口。
    T 是 anyClass 或其子类或是实现了 anyClass 接口的类。
    若未使用 extends 关键字限制泛型的类型参数,则默认是 Object 类下的所有子类。

    (4)泛型的类型通配符

    泛型类名<? extends T> o = null;    //上限通配。声明泛型类对象。`? extends T` 表示是 T 或 T 的未知子类或是实现接口 T 的类。
    泛型类名<? super T> o = null;    //下限通配。表示是 T 或 T 的一个未知父类型

    也可以用在方法参数中。
    function(Type<? extends T> o) {……}
    若只使用 ? 通配符,则默认是 ? extends Object,故 ? 称为非受限通配。
    直接用 <?> 创建泛型对象,有 2 个特点:
    a. 具有通用性,即该泛型类的其他对象可以赋值给用通配符 "?" 创建的泛型对象,反之不可。
    b. 用 "?" 创建泛型对象,只能获取或删除其中的信息,但不可为其添加新的信息。
    由于 JVM 只是在编译时对泛型进行安全检查,故要注意:
    a. 不能使用泛型的类型参数 T 创建对象。如 T obj = new T() 是错误的。
    b. 在泛型中可以用类型参数 T 声明一个数组,但不能使用类型参数 T 创建数组对象。如 T[] a = new T[个数] 是错误的。
    c. 不能在静态环境中使用泛型类的类型参数 T。
    d. 异常类不能是泛型的。即泛型类不能继承 java.lang.Throwable 类。

    (5)被定义为泛型的类或接口可被继承与实现

  28. 容器类
    容器框架的继承关系
    java
    (1)Collection 接口
    通常不能直接使用,提供了添加、删除元素、管理数据的方法。

    (2)List 列表接口
    包含有序元素的线性表,其中元素可重复,也可为空值 null。
    使用迭代器遍历容器;

    Iterator it = c.iterator();
    while (it.hasNext()) {
        Object o = it.next();
    }

    (3)Set 集合接口
    不含重复元素。

    • HashSet 哈希集合
      根据哈希码存取元素。
      哈希集合是在元素的存储位置和元素的值 k 之间建立一个特定的对应关系 f,使每个元素与一个唯一的存储位置相对应。因而在查找时,只要根据元素的值 k 计算出 f(k) 的值即可,若此元素在集合中,则必定在存储位置 f(k) 上,因此不需要与集合中其他元素比较便可直接取得所查元素。称 f 为哈希函数,按这种关系建立的表称为哈希表散列表
      HashSet 类不保证迭代顺序,允许元素值为 null。
      在比较 2 个加入哈希集合中的元素是否相同时,会先比较哈希码方法 hashCode() 的返回值是否相同,若相同,则再使用 equals() 方法比较其存储位置(内存地址);若两者都相同,则视为相同的元素。
      因为不同元素计算出的哈希码可能相同。若重写了元素对应类的 equals() 方法 或 hashCode() 方法,则必须重写另一个,以保证其判断的唯一性。
      上座率也称装填因子,值在 0.0~1.0 之间,表示集合的饱和度,当集合中的元素个数超过了容量与上座率的乘积,容量就会自动翻倍。
    • TreeSet 树集合
      工作原理与 HashSet 相似,但元素总是处于有序状态。当排序很重要时,应选择 TreeSet。

    (4)Map 映射接口
    元素成对出现。每个键都是唯一的且最多映射到一个值。

    • HashMap
      基于哈希表,通过哈希码进行查找,故添加和删除映射关系效率较高,且允许 null 值和 null 键,但必须保证键的唯一性。
    • TreeMap
      存在一定顺序,不允许键对象是 null。

Android学习笔记

《Android开发艺术探索》

  1. 当前 Activity 为 A,此时打开 Activity B:A.onPause() → B.onCreate() → B.onStart() → B.onResume() → A.onStop(),故不能在 onPause 中做重量级操作,使新 Activity 尽快显示出来并切换到前台。
  2. 当系统内存不足时,系统会按照 [ 后台 Activity → 可见但非前台 Activity → 前台 Activity ] 的优先级杀死目标 Activity 所在的进程。如果一个进程中没有四大组件在执行,那么这个进程将很快被系统杀死 → 故 将后台工作放入 Service 中从而保证进程有一定的优先级,不易被轻易杀死。
  3. Activity 的 LaunchMode
    (1) standard 标准模式(系统默认)—— 多实例实现
    每次启动一个 Activity 都会重新创建一个新的实例,被创建的实例的生命周期符合典型情况下 Activity 的生命周期。
    一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。
    谁启动了这个 Activity ,这个 Activity 就运行在启动它的那个 Activity 所在的栈中。
    当用 ApplicationContext 启动 standard 模式的 Activity 时会报错,因为非 Activity 类型的 Context 并没有所谓的任务栈,解决:为待启动的 Activity 指定 FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候会为它创建一个新的任务栈,此时待启动 Activity 实际是以 singleTask 模式启动的。
    (2)singleTop 栈顶复用模式

《Android 应用程序开发权威指南》

一、基础

  1. 管理器 功能
    LocationManager 和设备上的基于位置的服务进行交互
    ViewManager,WindowManager 负责显示界面以及设备相关的用户界面的基础
    AccessibilityManager 负责辅助事件,提供对物理损伤的用户的设备支持
    ClipboardManager 提供了访问设备全局剪贴板的能力,可以剪切和复制内容
    DownloadManager 作为系统服务,负责 HTTP 的后台下载
    FragmentManager 管理一个 Activity 的 Fragment
    AudioManager 提供了音频和振铃控制的访问
  2. 文件 功能
    AndroidManifest.xml 应用的核心配置文件。定义了应用程序的功能和权限,以及如何运行。
    ic_launcher-web.png 一张 32 位的 512*512 大小的高分辨率图标,用来在 Google Play 商店中显示。该图大小不能超过 1024KB。
    proguard-project.txt Android IDE 和 ProGuard 使用的编译文件。可以通过编辑该文件来配置代码优化选项,以及发布版本的混淆设置。
    project.properties Android IDE 中使用的编译文件。定义了应用程序的构建目标,以及其他编译系统选项。不要编辑这个文件
    /src 必须的文件夹,包含所有的源代码
    /gen 必须的文件夹,包含所有的自动生成的文件。
    /gen/.../BuildConfig.java 调试应用程序时,该源文件自动生成。不要编辑
    /gen/.../R.java 自动生成的资源管理的源文件。不要编辑
    /assets 必须的文件夹。包含了项目中未编译的资源文件,一些你不想作为应用程序资源管理的应用程序数据(文件、目录)
  3. 术语 描述
    Context(上下文) 是 Android 应用的**指挥中心。大部分应用特定的功能可以通过上下文访问或引用。Context 类是任何 Android 应用的基本构建模块,提供了访问应用程序范围的功能,譬如应用程序的私有文件、设备资源,以及整个系统的服务。应用程序的 Context 对象会被实例化为一个 Application 对象。
    Activity(活动) 一个 Activity 类是 Context 类的子类,因此它也拥有 Context 类的所有功能。
    Fragment(碎片) 一个活动有一个独特的任务或目的,但它可以进一步组件化,每一个组件被称为碎片。Fragment 类往往被用来组织活动的功能,从而允许在不同的屏幕大小、方向和纵横比上提供更灵活的用户体验。碎片常常用来在由多个 Activity 类组成的不同的屏幕上,使用相同的代码和屏幕逻辑放置相同的用户界面。
    Intent(意图) Android 操作系统使用异步的消息传递机制,将任务匹配到合适的 Activity。每一个请求被打包成一个意图。使用 Intent 类是应用程序组件如活动和服务之间通信的主要方法。
    Service(服务) 不需要用户交互的任务可以封装成一个服务。当需要处理耗时任务或需要定时处理时使用服务,用来处理后台操作。继承自 Context 类。
  4. 应用程序 Context
    因为 Activity 类是由 Context 类派生的,故有时可以使用它而不是显示地获取应用程序 Context。但不要在任何情况下都使用 Activity Context,因为可能会导致内存泄漏。

    • 获取应用程序资源,如字符串、图形、xml 文件。getResources()
    • 访问应用程序首选项 getSharedPreferences()
    • 管理私有的应用程序文件和目录
    • 获取未编译的应用程序资产 getAssets()
    • 访问系统服务
    • 管理自由的应用程序数据库(SQLite)
    • 以应用程序权限工作
  5. Activity 生命周期

    • onCreate() 初始化静态 Activity 数据

    • onResume() 初始化及取回 Activity 数据

    • onPause() 停止、保存和释放 Activity 数据,保存重要数据到用久存储,使用 onSaveInstanceState() 保存一些可以从当前屏幕快速恢复的数据或某些不重要的信息(如 未提交的表单数据或任何其他减少用户麻烦的状态信息)。

      停止任何声音、视频、动画,也必须停用资源如数据库游标对象 或 其他 Activity 终止时应该清理的对象。onPause() 可能是 Activity 进入后台时最后用来清理或释放不需要的资源的机会,需要在这里保存任何未提交的数据。
      调用 onPause() 后,系统保留杀死任何一个 Activity 而没有进一步通知的权利。
      Activity 需要在 onPause() 方法中执行快速的代码,因为只有 onPause() 方法返回后,新的前台 Activity 才会启动。
      一般来说,任何在 onResume() 方法中获取的资源和数据应该在 onPause() 方法中释放,否则当进程终止后,这些资源可能无法干净地释放。

      避免 Activity 被杀死
      内存不足时 Android 操作系统可以杀死任何暂停、停止或销毁的 Activity。这基本意味着任何没有在前台的 Activity 都会面临被关闭的可能。
      若 Activity 在 onPause() 后被杀掉,那么 onStop() 和 onDestroy() 方法将不会被调用。在 onPause() 方法内更多的释放 Activity 的资源,那么 Activity 就越不太可能在后台被直接杀掉(没有其他的状态切换方法被调用)。
      杀死一个 Activity 并不会导致它从 Activity 堆栈中的移除。若 Activity 实现并使用了 onSaveInstanceState() 用于自定义数据,Activity 状态将被保存到 Bundle 对象中(虽然一些 View 数据将会被自动保存)。当用户返回到 Activity 后,onCreate() 方法会被再次调用,这次会有一个有效的 Bundle 对象作为方法参数。

    • onDestroy() 销毁静态 Activity 数据
      当 Activity 通过正常的操作被销毁,onDestroy() 方法将会被调用。
      onDestroy() 会在 2 种情况下被调用:Activity 自己完成了它的生命周期,或因为资源问题,Activity 被 Android 操作系统杀掉,但仍有足够的时间从容销毁 Activity(与不调用 onDestroy() 方法直接终止 Activity 不同)。

      若 Activity 是被 Android 操作系统杀掉的,isFinishing() 方法会返回 false。该方法在 onPause() 中十分有用,可以知道 Activity 是否能够恢复。

  6. AndroidManifest.xml 清单文件
    作用:

    • Android 操作系统使用清单文件来安装、更新和运行应用程序包
    • 显示应用程序的详细信息,如名称、描述、图标
    • 指定应用的系统需求,包括对 Android SDK 的支持、设备配置的需求(如方向键),以及应用依赖的平台功能(如多点触摸)
    • 以市场过滤为目的,指定应用的哪些功能是必须的
    • 注册应用的 Activity,并指定如何启动
    • 管理应用程序的权限
    • 配置其他高级的应用组件配置详细信息,包括定义 Service、Broadcast Receiver 及 Content Provider
    • 为你的 Activity、Service 及 Broadcast Receiver 指定 Intent 过滤器
    • 为应用测试开启应用设置,如调试和配置仪器

    设置应用程序的系统需求:

    • <uses-feature> 标签用于指定应用需要哪些 Android 功能才能正常运行。这些设置只供参考不会强制使用。当使用 <uses-feature> 标签时,可以指定 android:required 的可选属性,并设置为 true 或 false,这个可以用于配置 Google Play 商店中的过滤。若该值为 true,Google Play 将只会在具有特定硬件或软件功能的设备上显示你的应用程序(如摄像头)。若应用程序需要多个功能,则必须为每个功能创建一个 <uses-feature> 标签。

      若应用正常运行时并不需要一个特定的功能,与其在应用商店内过滤并限制特定的设备,还可以使用 getPackageManager().hasSystemFeature() 在运行时检查特定的设备功能,并在用户的设备上支持该功能时才允许特定的功能,这样可以最大化安装和使用你应用的人群。

    • <uses-sdk> 标签用于指定应用程序支持的 Android 平台版本。应用商店会根据应用的清单文件的 <uses-sdk> 标签等的设置来为给定的用户过滤应用。忽略使用该标签将会在编译环境中产生一个警告信息。

    • <uses-configuration> 标签用于指定应用程序支持的硬件或软件的输入方法。有 5 个方向的配置属性:硬件键盘和键盘类型;方向设备如方向键、轨迹球和滚轮;触摸屏的设置。若应用程序支持多种输入配置,则必须有多个 <uses-configuration> 标签。

    • <supports-screens> 标签用于指定应用支持的 Android 屏幕类型。

    • 内的 <uses-library> 标签用于注册应用中链接到的外部库。

    • <supports-gl-texture> 用于指定应用支持的 GL 材质的压缩格式。使用图形库的应用使用该标签,并用于兼容可以支持指定压缩格式的设备。

    • <application> 标签属性中设置应用程序范围的主题。

    • <instrumentation> 设置单元测试功能。

    • <activity-alias> 为 Activity 起别名。

    • <receiver> 注册 Broadcast Receivers。

    • <provider> 注册 Content Provider,使用 <grant-uri-permission><path-permission> 管理 Content Provider 的权限。

    • <meta-data> 包含应用的 Activity、Service、Receiver 组件注册的其他数据。

  7. 管理资源

    • 所有 Android 应用程序由 2 部分组成:
      功能部分——代码指令(程序运行的任何算法)
      数据部分——资源(文本字符串、样式主题、尺寸、图片图标、音视频文件等)

    • 默认 Android 资源目录,所有资源必须存放在项目的 /res 目录下的指定子目录,且目录名必须小写。

      资源子目录 内容
      /res/drawable-*/ 图形资源
      /res/layout/ 用户界面资源
      /res/menu/ 菜单资源,用于显示 Activity 中的选项或操作
      /res/values/ 简单的数据,如字符串、样式主题、尺寸资源
      /res/values-sw*/ 覆盖默认的尺寸资源
      /res/values-v*/ 较新 API 自定义的样式和主题资源
    • 常见的资源类型及存储结构

      资源类型 所需目录 建议文件名 XML 标签
      字符串 /values/ strings.xml <string>
      字符串复数形式 /values/ strings.xml <plurals>, <item>
      字符串数组 /values/ strings.xml 或 arrays.xml <string-array>, <item>
      布尔类型 /values/ bools.xml <bool>
      颜色 /values/ colors.xml <color>
      颜色状态列表 /color/ 包括 buttonstates.xml, indicators.xml <selector>, <item>
      尺寸 /values/ dimens.xml <dimen>
      ID /values/ ids.xml <item>
      整型 /values/ integers.xml <integer>
      整型数组 /values/ integers.xml <integer-array>
      混合类型数组 /values/ arrays.xml <array>, <item>
      简单可绘制图形(可打印) /values/ drawables.xml <drawable>
      XML 文件定义的图形(如形状) /drawable/ 包括 icon.png, logo.jpg 支持的图形文件或可绘制图形
      补间动画 /anim/ 包括 fadesequence.xml, spinsequence.xml <set>, <alpha>, <scale>,<translate>, <rotate>
      属性动画 /animator/ mypropanims.xml <set>, <objectAnimator>, <valueAnimator>
      帧动画 /drawable/ 包括 sequence1.xml, sequence2.xml <animation-list>, <item>
      菜单 /menu/ 包括 mainmenu.xml, helpmenu.xml <menu>
      XML 文件 /xml/ 包括 data.xml, data2.xml 开发者定义
      原始文件 /raw/ 包括 jingle.mp3, video.mp4, text.txt 开发者定义
      布局 /layout/ 包括 main.xml, help.xml 多样,但必须是布局类型
      样式和主题 /values/ styles.xml, themes.xml <style>
    • 使用字符串资源

      • 所有包含撇号及单引号的字符串需要被转义 "" 或被双引号包裹
      • 可使用 HTML 样式的属性(粗体、斜体、下划线标签)
      • 忽略格式:String s = getResources().getString(R.string.hello);
      • 保留字符串格式:
        CharSequence cs = getResourece().getText(R.string.hello);
        ②使用 TextUtils 的 htmlEncode()
  8. TexdView 文本中创建上下文链接:autoLink 属性

    描述
    note 禁用所有链接
    web 允许 web 网页的 URL 链接
    email 允许电子邮件地址链接,并在邮件客户端填写收件人
    phone 允许电话号码链接,可以在拨号器应用中填写电话号码来拨打
    map 允许街道地址的链接,可以在地图应用中显示位置
    all 允许所有类型的链接

    开启 autoLink 功能依赖于 Android SDK 中的各种类型的检测。有时候也可能链接不正确或产生误导。

  9. EditText

    • 输入过滤器限制输入
      使用 setFilters() 来设置 InputFilter 限制用户输入,InputFilter 接口包含一个 filter() 方法。可以实现 InputFilter 接口来创建自定义的过滤器。setFilters() 的参数是 InputFilter 对象的数组,这对于组合多个过滤器是非常有用的。
    • 自动完成
      • AutoCompleteTextView :基于用户输入的内容来填写整个文本。
      • 允许用户输入字符串列表,每一个都具有自动完成功能。这些字符串都要以某种方式分隔,提供给 MultiAutoCompleteTextView 对象的Tokenizer 来处理。这对于指定通用标签等的列表有所帮助。也可以自己实现 MultiAutoCompleteTextView.Tokenizer 接口,内置逗号分隔符 CommaTokenizer()

Android Tips

  1. ScrollView 嵌套 ListView
    自定义可适应 ScrollView 的 ListView,重写其 onMeasure 方法。
    此方法默认显示的首项是 ListView,需要手动把 ScrollView 滚动至最顶端:scrollView.smoothScrollTo(0, 0);

    import android.content.Context;
    import android.util.AttributeSet;
    import android.widget.ListView;
    public class ListViewForScrollView extends ListView {
        public ListViewForScrollView(Context context) {
            super(context);
        }
        public ListViewForScrollView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public ListViewForScrollView(Context context, AttributeSet attrs,
            int defStyle) {
            super(context, attrs, defStyle);
        }
        @Override
        /**
         * 重写该方法,达到使 ListView 适应 ScrollView 的效果
         */
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
            MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);
        }
    }

    参考:四种方案解决 ScrollView 嵌套 ListView 问题

  2. ListView 屏蔽 item 点击

    • 在 ListView 中设置:

      • 若 ListView 的 id 是使用系统默认的 id,则可以在实现此 ListView 的 Adapter 里重写 isEnabled() 方法:

        <ListView android:id="@android:id/list"
              android:layout_width="match_parent" 
              android:layout_height="match_parent"
              android:transcriptMode="alwaysScroll"
              android:layout_weight="1"
        />
        
        @Override    
        public boolean isEnabled(int position) {     
             return false;     
        }  
      • 若 ListView 的 id 是自定义的

        listview.setEnabled(false);

      参考: android 之 listview 的 item 不可点击

      以上方法会导致 ListVIew 无法滑动,只适用于在 ScrollView 中的 ListView。

    • 在 Adapter 中设置

        //表明 Adapter 中的所有 item 是否可以点击 
        @Override
        public boolean areAllItemsEnabled() {
            return false;
        }
        //表明下标为 position 的 item 不可选中,不可点击
        @Override
        public boolean isEnabled(int position) {
            return false;
        }

      参考: android 屏蔽 listview 的item事件

    • 屏蔽 HeaderView、FooterView 点击

      mListView.addHeaderView(headView ,null,false);  

      参考:如何让 listView 加入的 HeaderView 不可点击

  3. ListView 不显示分割线

    • 设置和取消每个 item 分隔线

      listView.setDivider(null);
      android:divider="@null";
      android:divider="@drawable/listview_horizon_line"
    • 隐藏头部分隔线
      Listview 分割线会在头部、数据 item 底部打印,如果要取消头部分割线必须
      先设置其方法

      addHeaderView(headView, null, true);
      addFooterView(footView, null, true);
      
      **注意:第三个参数必须为 true,否则无效**
      //显示头部出现分割线
      listview.setHeaderDividersEnabled(true);
      //禁止底部出现分割线 
      listview.setFooterDividersEnabled(false);

    参考:Android 技术之 ListView 分割线显示和隐藏

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.