Java学习笔记

Posted on March 27, 2014

背景和环境

JDK JRE JVM的关系

环境变量

  • JAVA_HOME 它指向jdk的安装目录,Eclipse/NetBeans/Tomcat等软件就是通过搜索JAVA_HOME变量来找到并使用安装好的jdk

    配置: 对于mac, 在启动的配置文件中添加:

    export JAVA_HOME=`/usr/libexec/java_home`
    

    测试:

    % echo $JAVA_HOME
    /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home
    

执行与部署

  • 指定输出目录编译: javac -d ../classes MyApp.java

    对有包名的: javac -d ../classes com/fox/MyApp.java

    编译所有: javac -d ../classes com/fox/*.java

  • 打包: jar -cvmf manifest.txt app.jar MyApp.class

    会生成app.jar包, manifest.txt 中指定Main Class: Main-Class: MyApp

    对于有包名的: jar -cvmf manifest.txt app.jar com 只要指定com, 下面的都会自动扩展

  • 执行jar包: java -jar app.jar

  • 列出jar包内容: jar -tf app.jar tf表示table file

  • 解压jar包: jar -xf app.jar

  • jar 常用参数

    • -c 创建新的存档
    • -v 生成详细输出到标准输出上
    • -f 指定存档文件名

声明规则

  • 一个源文件中只能有一个public类
  • 一个源文件可以有多个非public类
  • 源文件的名称应该和public类的类名保持一致
  • 如果一个类定义在某个包中,那么package语句应该在源文件的首行
  • 如果源文件包含import语句,那么应该放在package语句和类定义之间

  • .java 文件编译后, 每个java类都有一个class文件

  • 包名必须全部小写

  • 自动引入的包 java.lang 包括System, String, Math等


修饰符

修饰符用来定义类、方法或者变量,通常放在语句的最前端

访问修饰符:

逐渐严格:

  • public: 对所有类可见, 类所有的公有方法和变量都能被其子类继承
  • protected: 对同一包内的类和所有包内外子类可见 (2个条件是或关系, 满足一个就行)
  • 默认的,也称为default: 在同一包内可见, 父类中默认修饰符声明的方法,能够在子类中声明为private
  • private: 在同一类内可见, 类和接口不能声明为private, 父类中声明为private的方法,不能够被继承

非访问修饰符

  • static
    • 静态变量(类变量)
    • 静态方法(类方法)
    • 静态import, import stati bao.Class.method 然后method就可以在该文件中直接使用
    • 类加载时执行代码: static {...code...} 对象初始化时执行代码 {...code...}, 且先于构造函数执行
  • final
    • Final变量:

      Final变量能被显式地初始化并且只能初始化一次

      被声明为final的对象的引用不能指向不同的对象。但是final对象里的数据可以被改变。也就是说final对象的引用不能改变,但是里面的值可以改变

      作为实例变量或者类常量(加上static)

    • Final方法: 表示该方法可以被继承, 不能被覆盖

    • Final类: 不能被继承

  • abstract

    • 抽象类
    • 抽象方法
  • synchronized

  • transient

  • volatile

类型

primitive类型

  • primitive类型(4整2浮1字符1bool)

    • byte 8位
    • short 16位
    • int 32位
    • long 64位
    • float 32位 字面量需要加上f 如32.4f
    • double 64位 带小数的数字默认是此类型
    • char 16位 字面量用单引号
    • boolean
  • 包装类型(引用类型)

    • Byte
    • Short
    • Integer
    • Long
    • Float
    • Double
    • Character
    • Boolean
  • primitive变量存的是变量实际的值,但对象变量存的是对象在堆上的引用,我们不关心对象变量占多少字节, 对同一个JVM,所有对象变量的字节数相同

  • 需要boolean判断的表达式不能用其他类型代替,如while(1) {....}不合法

引用类型

  • 所有引用类型的默认值都是null

  • 对象、数组都是引用数据类型

  • 数组

    • 数组一定是对象,数组里存的全是变量
    • 数组字面量定义使用花括号 String[] x = {"a", "b"}
    • 加强版的数组遍历: for (ItermType i : someArray) {...} ItermType 表示数组的类型
  • String

    需要双引号

变量

局部变量:

  • 局部变量存在于方法调用时的栈上,所有对象存在于堆上,实例变量存在于所属对象的堆上。

  • 局部变量没有默认值,所以局部变量量被声明后,必须经过初始化,才可以使用

  • 所以如果局部变量指向一个对象,只有变量本身是在栈上,对象本身在堆上。

实例变量:

  • 实例变量具有默认值

  • 变量的值可以在声明时指定,也可以在构造方法中指定

类变量(静态变量):

  • 静态变量在程序开始时创建,在程序结束时销毁

  • static变量/实例变量可以在定义时设置初始值, 如果没有设置将会有默认值 0/0.0/false, 引用的默认值是null

常量:

  • static final CONST_NAME 按照命名规范,常量要全部大写, 常数在定义时必须初始化

赋值:

  • java变量赋值是值传递 也就是拷贝变量的字节内容,对于primitive就是复制内容,对于对象变量就是复制对象的引用地址(因为对象变量存的字节内容是对象的引用)

  • 变量赋值时,如实参赋予形参,方法返回值等,类型都可以隐式变大,或者显式变小

  • == 变量比较时是比较字节序列,所以primitive是比较内容,对象变量则是比较是不是存的同一个引用


面向对象

  • 这句话很吊:封装的优点是能让你三心二意却又不伤害别人

  • 编译器是根据引用(变量)的类型来判断哪些method可以调用, 而不是引用实际的对象的类型

    如果要判断引用的实际类型, 可以使用表达式 someObject instanceof SomeClass

  • 类中 this 是当前对象的引用

  • 构造函数

    • 构造函数名与类名相同
    • 不能有返回值
    • 有返回值的同名函数是合法的,这只是一个普通函数
    • 构造函数不会被继承, 但是当创建子类对象时,所有继承链上的构造函数都会执行,包括abstract类的
    • 构函链的调用,相当于是编译器在每个子类构函第一句加上了super() 也就是说编译器只会自动调用无参构函
    • 所以如果需要调用有参父类构函,需要手动调用super(...)
    • 显式调用父类构函,必须在第一句super(...)
    • 构函可以重载,以实现用不同参数(个数,类型)来初始化
    • 在没有显示定义构造函数时,编译器会提供一个无参构函
    • 在构函中,可以通过 this(...)调用当前类的另外一个参数不同的构函。
    • 在构函中this(..) super(...) 只能出现一个,而且必须是第一句
  • 覆盖

    • 可见性只能相同或者更可见,不能缩小可见性, 但是覆盖实例变量不受此限制
    • 方法的参数类型个数必须完全相同,返回值可以相同或者是子类型。否则就不是覆盖而是重载
  • 重载

    • 不能只改变返回类型,参数类型或个数要改变
    • 可以改变可见性
    • 和多态无关
  • 多态:

    • 子类对象可以赋给父类引用
    • 通过多态,可以写出引入新子类也不用修改代码的程序
    • 指向了子类对象的父类引用只能调用父类定义了的方法(编译期检测),子类新增的方法无效。运行期将调用子类的方法
  • abstract类

    • 可以有abstract方法,也可以有具体方法
    • 有abstract方法的类一定是abstract类
    • abstract类可以作为变量类型,承载子类对象
    • abstract类的abstract子类选择可以实现abstract方法,非abstract子类必须实现abstract方法
  • Object

    • Object是所有对象的父类,没有显示继承其他父类的类,都隐式继承Object
    • 主要方法:
      • equals(Object o)
      • getClass() 返回所属类
      • hashCode()
      • toString()
  • 接口

    • 可以理解为所有方法都是无内容且抽象的方法
    • 接口的子类必须实现所有方法
    • 一个类只能extend一个父类,但是可以implement多个接口
    • 设计对象扮演某种角色 往往需要使用接口(aspect-oriented)
    • 接口中所有的方法都是public abstract
  • 子类中调用父类方法:super.method_name(..)可以调用非同名方法,调用时机可以在任何时刻,不用在方法中第一行

  • static方法不能调用非static方法和实例变量,但一个类的对象可以调用static方法(但不推荐,引起误解,其实会转会成类来调用)

  • 堆和栈

    对象在堆, 实例变量存在所属的对象中, 但实例变量分primitive和对象, 前者在对象空间内, 后者的引用在对象空间内

    对象的引用变量在栈

    方法调用在栈, 局部变量在栈, 局部变量如果引用了对象, 那么变量在栈, 对象始终在堆


异常

  • 如果方法会throw异常, 方面签名上需要声明functionname() throws SomeException

    方法可能抛出多种异常, 需要都声明, 或者只声明他们的公共父异常

    不过如果异常是RuntimeException, 可以不用声明

  • RuntimeException 通常是程序逻辑错误, 是应该在开发测试阶段发现避免的, 因此通常不需要try catch

    其他类型错误通常是运行期间无法预料和避免的, 如网络错误

  • 如果try或catch中有return, finally还是会执行, 会先finally然后再会到return指令


反射相关

  • java.lang.Class 用于封装被装入到JVM中的类(包括类和接口)的信息

    当一个类或接口被装入的JVM时便会产生一个与之关联的java.lang.Class对象(类对象)

  • 类名加“.class” 返回该类对应的类对象

  • java.lang.Object#getClass 返回该对象的类对象

    public final Class getClass()

  • java.lang.Class#getName() 返回类对象的字符串名称

    public String getName()


其他

  • 学习的秘诀

    如果你的思路堵塞了, 试着把内容大声地念出来. 说话与倾听都会使用到大脑的不同位置. 虽然与人交谈效果最好, 但是对着宠物念也会有帮助. 我家的狗狗就是这样学会JSP的.

  • && || 是短路运算,只能用于boolean与boolean,&| 是非短路运算,可以用于boolean与boolean(返回boolean),也可用于位运算int与int

  • 自动引入的包 java.lang 包括System, String, Math等

  • final

    • 实例变量,局部变量,方法参数: 表示该变量不能修改
    • 方法:表示该方法不能被覆盖
    • 类:表示该类不能被继承
  • brew install javarepl

    http://github.com/albertlatacz/java-repl


Eclipse

  • 补全: Preferences——>Java-->Editor-->Content Asist,在Auto activation triggers for Java后面的文本框里只有一个“.”。现在你将其改为“.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”即可

    syso:

    syse:

    貌似alt+/是呼出自动补全

  • 全文调整缩进: cmd+shift+f

  • 快捷修复: command+1 或者F2+回车选择第一个修复

  • 快捷删除: command+D

  • 开启新的一行: shift+回车 类似VIM中的o

  • 运行: command+F11

  • 移动行: alt + 上下光标, 还可以光标选中移动多行数据

  • 复制行: alt + command + 上下光标

  • 放大/缩小视图: Ctrl+M

  • 批量注释: command+/

  • /**回车 生成java doc注释


注解

Annotation是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符.

用一个词就可以描述注解,那就是元数据,即一种描述数据的数据. 所以, 可以说注解就是源代码的元数据.

因为注解是由编译器计算而来的, 因此, 所有的元素值必须是编译期常量.

元注解

@interface

@Target

@Retention

获取注解

  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

    该项是否有指定注解

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass)

    传入注解类型, 获得该注解的对象

    此方法定义在接口AnnotatedElement中, Method, Constructor, Field, Class和Package都实现了此接口.

  • Annotation[] getDeclaredAnnotations()

    获得该项声明的所有注解, 不包括继承而来的注解.