Java语言规范是Java语法和语义技术性定义,API是应用程序接口(Java预定义类和接口),Java开发工具包(JDK)包含软件库、编译器、解释器以及其他工具,集成开发环境(IDE)提供编辑、编译、调试和在线帮助功能。
Java平台版本: Java SE:允许开发和部署在桌面、服务器和嵌入式环境和实时环境中使用的Java应用程序。 Java EE:它帮助开发和部署可移植、健壮、可伸缩且安全的服务器端Java应用程序。Java EE是在Java SE的基础上构建的,它提供web服务、组件模型、管理和通信API。 Java ME:它为在移动设备和嵌入式设备上运行的应用程序提供一个健壮且灵活的环境。 Java运行环境Java的目标代码可以在任何平台上运行,Java的源代码编译之后生成.class文件,由字节码构成(比如博客之前安卓逆向研究的Dalvik字节码)。字节码可以在任何装有Java虚拟机的计算机上运行,Java虚拟机是一个用于解释字节码的软件。
Java程序剖析: 注释:Java程序包含三种注释,即多行注释、单行注释、文档注释,多行注释,修饰符:常见如public, protected, private, static, abstract, final,用于指定数据、方法、类的属性以及它们的用法。 类:是Java的基本结构,一个程序可以包含一个或多个类,一个Java源文件里最多只有一个公有类。 main方法:Java解释器通过调用main方法执行应用程序。 常量: 一旦初始化后就不能再改变的数据,语法为final datatype CONSTANT_NAME = value; Java数据类型 Java数据类型:包括基本类型和引用类型,
基本类型包括 整数类型(byte, short, int, long) 字符类型(char)浮点类型(float, double)逻辑类型(boolean);引用类型包括 类,接口,数组。其中,浮点数中以d或D结尾或者无后缀表示double类型,以f或F结尾的表示float类型;整数字面值中以l或L结尾的表示long类型,其他表示int类型。 Java数值类型转换:
如果有一个操作数是double类型,另一个操作数转换为double 类型;否则,如果有一个操作数是float类型,另一个操作数转换为float类型;否则,如果有一个操作数是long类型,另一个操作数转换为long类型;否则,两个操作数都转换为int类型;数据转换总是向较大范围的数据类型转换,避免精度损失。
将值赋值给较大取值范围的变量时,自动进行类型转换;
将值赋值给较小取值范围的变量时,必须使用强制类型转换。 字符数据类型:char表示16位的单个Unicode字符,char类型的字面值 包括以两个单引号界定的单个Unicode字符,可以用uxxxx形式表示的, 转义字符表示n t b r f ` ” 。 编程风格:
良好的编程风格有利于减少错误,产生容易阅读、易于理解的代码。类和方法前使用文档注释,方法步骤前使用行注释;变量和方法名使用小写,如果有多个单词,第一个单词首字母小写,其他单词首字母大写;类名的每个单词的首字母大写;常量使用大写,单词间以下划线分割。
Java常见错误类型:包括语法错误,即在编译期间产生的错误;运行时错误,导致程序非正常终止的错误;逻辑错误,程序不能按预期的方式执行,编译不会报错。
条件语句:包括If语句、switch语句、条件表达式,其中的if语句判断条件必须是boolean类型的;在if-else条件语句中,else语句与同一块中最近的if语句匹配。在使用条件语句中,避免在条件表达式中使用比较操作符判断布尔变量的真假。switch语句的判断条件expression的计算结果只能是byte, char, short, int。value1-valueN必须与 判断条件类型相同,且为常量表达式,不能是变量。
Java中常用的数学函数: Math.random方法生成[0.0,1.0)之间的double类型的随机数,可以用它写出简单的表达式来生成任意范围的随机数,一般地,a + (int)(Math.random() * b)返回[a, a+b);还可以用该方法生成随机字符,Java中每个字符对应一个Unicode编码从0000到FFFF,在生成一个随机字符,就是产生一个0到65535之间的随机数,所以计算的表达式为(int)(Math.random() * (65535+1))。生成任意2个字符ch 1和ch2(ch1 < ch2)之间的随机字符,(char)(ch1 + (int)(Math.random() * (ch2 – ch1 + 1))) 字符数据类型和操作 在字符型数据和数值类型数据之间转换时,如果转换结果适用于目标变量(不会有精度损失),可以采用隐式转换;否则必须使用强制类型转换。 所有数值运算符都可以用在char型操作数上,如果另一个操作数是数值或字符,那么char型操作数就自动转换为数值;如果另一个操作数是字符串,那么char型操作数就会自动转换成字符串再和另外一个操作数字符串相连。 字符串类型
String类型是不可变的,其内容是不可修改的;如以下代码片段:
String s = "java";s = "HTML";12
其中s可以理解为一个对象指针,其指向对象空间,其中的字符串为java,第二句赋值只是将s指向了另一个对象空间。
equals方法用于比较两个字符串是否包含相同的内容。 equalsIngoreCase忽略大小写比较内容是否相同。 regionMatch比较部分内容是否相同。 startsWith判断是否以某个字符串开始。 endsWith判断是否以某个字符串结束。 compareTo方法用于比较两个字符串的大小,即第一个不同字符的差值. 调用length()方法可以获取字符串的长度。。 charAt(index)方法可以获取指定位置的字符,index必须位于0到s.length()-1之间。 concat()方法用于连接两个字符串,连接操作返回一个新的字符串。 indexOf返回字符串中字符或字符串匹配的位置,返回-1表示未找到。indexOf指定第二个参数表示从指定的位置开始查找。 toCharArray将字符串转换成字符数组。valueOf方法将基本数据类型转换为字符串,例如转化为字符串,如String s1 = String.valueOf(1.0); String s2 = String.valueOf(true);;字符串转换为基本数据类型,Double.parseDouble(str)等。 方法: 方法签名指方法名称、参数类型、参数数量和返回类型;==一个类中不能包含签名相同或仅返回类型不同的多个方法;==方法头中声明的变量称为形参,**形参可以使用final修饰,表示方法内部不允许修改该参数;**形参不允许有默认值,最后一个可为变长参数。方法可以有返回值,构造函数没有返回值。 如果方法声明中含有形参,调用方法时必须提供实参,实参的类型必须与形参的类型兼容:如父类形参可用子类实参。 调用方法时,基本数据类型的实参值的副本被传递给方法的形参,方法内部对形参的修改不影响实参值;对象类型的参数是引用调用。 方法重载: 方法重载是指方法名称相同,但方法签名不同的方法,仅返回类型不同不可重载。一个类中可以包含多个重载的方法。 当调用方法时,Java编译器会根据实参的个数和类型寻找最准确的方法进行调用;调用时匹配的方法多于一个,则会产生编译错误,成为歧义调用。 数组: 数组是引用类型。 多维数组只是数组的数组,故数组元素也可能是引用类型变量 凡使用new后,内存单元都初始化为0或Null。 声明数组引用变量,datatype[] arrayRefVar;,任何实例化的数组都是Object的子类。 数组变量是引用类型的变量,声明数组变量并不分配内存空间,必须通过new实例化来分配内存空间。 新创建的数组其元素根据类型被初始化为默认的初始值,数值类型为0字符类型为’u0000’布尔类型为false引用类型为null 数组可以在声明的括号后提供初始值,double[] mylist = {1.9, 2.9, 3, 3.5};或者double[] mylist = new double[]{1.9, 2.9, 3, 3.5}; 数组的大小在创建这个数组之后不能被改变,arrayRefVar.length可以访问数组的长度。 直接使用赋值语句不能实现数组复制,结果是两个数组引用变量指向同一个数组对象。在将数组作为实参传递给方法时,修改形参引用的数组,将改变实参引用的数组。 JVM将数组存储在叫堆的内存区域里,数组引用存储在栈空间中。 String传递给方法:由于实参的字符序列不可修改,将克隆给形参。 可以把类型相同,但个数可变的参数传递给方法,方法中的参数声明为typeName…parameterName,==Java将可变长参数当数组看待,通过length属性得到可变参数的个数。
print(String...args){//可看作String[] argsfor(String temp: args)System.out.println(temp);System.out.println(args.length);}12345
java.util.Arrays类包括各种静态方法,其中实现了数组的排序和查找,即sort方法与binarySearch方法。 二维数组的每个元素(数组)的长度可以不同,创建二维不规则数组时,可以只指定第一维下标,第一维的每个元素为null, 必须为每个元素使用new创建数组。 面向对象思考: 类间的关系描述方法,关联关系:是一种通用的二元关系,对象间通过活动发生联系,例如学生选学课程,教师教授课程。==在Java中,关联关系可以用数据域或方法来实现,对于方法,一个类中的方法包含另一个类作为参数。 聚合关系是一种拥有关系,表示整体与部分之间的关系,即Has-a的关系,在聚合关系中,一个对象可以被多个聚集着拥有; 组合关系是一种隶属关系,一个从属者只能被一个聚集着拥有。如一个Name对象只能为一个Person所拥有,但一个Address对象可以被多个Person所共享。 继承关系,表示子类与父类之间的is-a关系,通过继承,子类可以重用父类的数据和代码。 实现关系,表示接口和类之间的关系,类实现接口。 继承: 继承是一种软件重用,如果没有继承,会出现很多重复定义。语法为:
class ClassName extends Superclass{classbody}123
子类继承了父类中可访问的数据域和方法,子类也可添加新的数据域和方法,子类不继承符类的构造函数。一个子类只能有一个直接父类:单继承。子类继承的父类的私有属性不能访问,但是可以通过所继承的get和set公有方法设置和访问。
当第一次创建子类对象时,首先初始化其父类静态成员变量(如果没有父类对象),然后初始化当前子类对象的静态成员变量。注意:第一次之后创建子类对象时,不会再次初始化父类和子类的静态成员变量。其实,静态成员变量在有任何实例变量对象之前已经存在。接着执行该子类对象的父类的构造函数super(…),可能是编译为父类提供的默认无参构造函数super()。然后执行子类实例变量定义时的初始化表达式,若定义时未给出初始值,则默认为0或null.最后执行子类构造函数中super(…)后面的语句。 super关键字:super调用父类的构造函数,必须是子类构造函数的第一条且仅一条语句(先构造父类),如果子类构造函数中没有显示地调用父类的构造函数,那么将自动调用父类不带参数的构造函数。 如果父类属性或方法可以在子类访问,则使用super.data或者super.method(parameters)进行访问。 super与无参构造函数:如果一个类自定义了构造函数(不管有无参数),系统不会自动加上无参构造函数; 反之,如果没定义则会加上。编译在为子类添加无参构造函数时,用super()默认调用父类的无参构造函数,如果找不到父类的无参构造函数,则子类添加无参构造函数失败。 所以,如果一个类定义了带参数的构造函数,一定别忘了定义一个无参构造函数。 实例方法覆盖 如果子类重新定义了从父类中继承的实例方法,称为方法覆盖。 仅当方法是**可访问的实例方法**时,才能被覆盖,即私有实例方法不能被覆盖,私有方法自动视为final. (final修饰类时表示其不可被继承;修饰方法表示不可在子类中被重写;修饰成员变量时表示只能在声明处或者构造函数中初始化一次)。 静态方法不能被覆盖,如果静态方法在子类中重新定义,那么父类方法将被隐藏。 一旦父类中的方法被覆盖,则不能通过引用的子类对象访问被覆盖的父类方法。在子类类体函数中可以使用super引用被覆盖的父类方法。 隐藏和覆盖的区别:覆盖,子类对象被父类引用变量引用,父类引用变量调用的相同签名的函数是子类函数(不能发现父类函数,晚期绑定);隐藏,同上,但父类引用变量访问的是父类变量、函数(可以在发现)。 子类方法同样可以与父类中可访问的方法构成重载。 多态和动态绑定:
重载发生在编译时,编译时编译器根据方法签名找到最合适的方法;多态发生在运行时,运行时JVM根据变量所引用的对象的真正类型来找到最合适的实例方法。多态是晚期绑定,绑定是指找到函数的入口地址的过程。
访问控制符和修饰符final成员修饰符本类本包子类它包publicyyyyprotectedyyyn无(package)yynnprivateynnn
父类私有成员在子类不可见; 父类公有和保护成员在子类可见 继承到子类后不改变父类成员的访问权限。 异常处理: 一般而言,带有异常处理的程序会写成try…catch的形式;在try体内完成程序的正常处理流程,在catch体内完成异常处理。 若正常的异常处理出现错误,则使用”throw <异常对象引用>”抛出异常;抛出的异常由catch捕获,未被捕获的异常逐层传播到main,如果main也没有处理该异常,则操作系统会终止main执行。 抛出而未捕获(未处理)异常的函数,必须用throws声明其未处理的这些异常。有些异常是系统抛出的,程序只需要捕获处理即可。 异常的捕获顺序:无论何时,throw以后的语句都不会执行;无论同层catch是否捕获、处理本层的异常(即使抛出或转发异常),同层的finally总是都会执行。 一个catch捕获到异常后,同层catch都不会执行,然后执行同层finally; 一个同层try-catch-finally结束,若无异常则执行其后语句,若有异常,则跳过其后语句,进入上层catch流程。上图中红色标出的为div的执行轨迹。 自定义异常类:
自定义异常类必须继承Throwable或其子类;自定义异常类通常继承Exception及其子类,因为它是程序可处理的类。自定义异常类会在父类的基础上增加成员变量,因此,通常需要覆盖toString函数(经常被打印)。未增加新成员就没有必要自定义异常类。自定义异常类通常不必定义clone, equals:捕获和处理异常时通常只是引用异常对象而已。
抽象类: Java可定义不含方法体的方法,其方法体由子类根据具体情况实现,这样的方法称为抽象方法,包括抽象方法的类必须是抽象类。抽象类和抽象方法的声明必须加上abstract关键字。 类C如果满足下面任一条件,则该类包含抽象方法且是抽象类:类C显示地进行一个抽象方法的声明;类C的父类中声明的抽象方法未在类C和它的父类中实现;类C的接口中声明一个方法,并且类C未实现该方法;只有类C有一个为实现的方法,类C就是抽象类。 抽象类不能被实例化,即不能用new关键字创建对象;抽象类可以定义构造函数,可以被子类调用;具体子类必须实现抽象父类中所有抽象方法,否则子类需要声明为抽象类;抽象类只能用具体子类的对象实例化。 接口:接口是公共静态常量,公共静态方法和公共抽象方法,默认实例方法的集合。接口中的一切都默认是public的,没有修饰符的方法默认是abstract的,数据成员默认是static的。
接口不能定义构造函数,一个接口可继承extends多个接口,接口不能被类extends,一个类可实现implements多个接口。
public interface I1{public static final int k = 1;public abstract void m();}1234
等价于:
public interface I1{int k = 1;//=1不可省略,因为默认是public static final的,必须初始化void m();//不可定义函数体,默认是public abstract.}1234
接口中的方法通过“接口类型的引用变量.方法名”调用,但接口类型的引用变量必须引用实现了该接口的具体类的实例对象。接口中的常量名通过”接口名.常量名”访问。