#
Java
#
1. java标识符
- 标识符以字母,美元符号和下划线开头
- 首字符之后可以是字母,美元符号,下划线和数字的任意组合
- 大小写敏感
- 关键字不能做标识符
#
2. java注释
单行注释
使用//
开始
多行注释
以/*
开始,以*/
结束
文档注释
以/**
开始,以*/
结束
#
3. java对象和类
- 类(Class),定义对象的属性和方法。
- 对象(Object),类的实例。
- 继承,一个类可以继承另一个类的属性和方法。
- 封装,将对象的字段私有化,通过公共方法访问。
- 多态,通过方法重载和方法重写实现。
- 抽象,使用抽象类和接口来定义必须实现的方法,不提供具体实现。
- 接口(Interface),定义类必须实现的方法,支持多重继承。
- 方法,定义类的行为,包含类中的函数。
- 方法重载(overload),同一个类中可以有多个同名的方法,但是参数不同。
类的变量
- 局部变量:在方法,构造方法或者语句块中定义的变量为局部变量。变量声明和初始化都在方法中,方法结束后,变量就会自动销毁。
- 成员变量:成员变量定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中的方法,构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。类变量与类相关,无论创建多少个类实例,静态变量在内存中只有一份,被所有实例共享。可通过类名或实例名访问。
- 参数变量:用于接收传递给方法或构造函数的值。参数变量的值传递有两种方式:(1)值传递,java基本数据类型都是采用值传递。值传递传递的是参数的值的副本,只会修改副本而不会影响原始值。(2)引用传递,java中的对象类型采用引用传递。传递的是实际参数的引用,会修改原始值的内容。
构造方法中的this关键字
- 引用当前对象的属性或方法
public Person(String name, int age) {
this.name = name; // this.name 表示类的属性
this.age = age;
}
- 调用另一个构造方法。使用this()调用当前类的其他构造方法,必须放在当前构造方法的第一行。
public Person(String name) {
this(name, 0); // 调用另一个双参数的构造方法
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
#
4. java基本数据类型
#
内置数据类型
六种数字类型(四个整数类型,两个浮点型),一种字符类型,一种布尔型。
整数类型
- byte(8位)
- short(16位)
- int(32位),整型默认为int类型。
- long(64位),使用"L"或"l"后缀。 浮点型
- float(单精度,32位)
- double(双精度,64位),浮点型默认为double类型。 字符型
- char 布尔型
- boolean
#
引用数据类型
- 引用类型指向一个对象,指向对象的变量是引用变量。变量被声明后,类型就不能改变了。
- 对象,数组都是引用数据类型。
- 所有引用类型的默认值都是null。
#
常量
使用final关键字来定义常量,常量标识符通常全是大写。
#
5. java修饰符
#
访问控制修饰符
- public,类,变量,接口,方法。
- private,变量,方法。不能修饰类。
- default,类,接口,变量,方法。
- protected,变量,方法。不能修饰类,内部类除外。
子类与基类不在同一包,在子类中,子类实例可以访问从基类继承而来的protected方法,而不能访问基类实例的protected方法。
#
非访问修饰符
- static,静态变量,静态方法。静态方法不能使用类的非静态变量。
- final,final变量,一旦赋值后,不能被重新赋值。final方法,父类中的final方法可以被子类继承,但不能被重写。final类,不能被继承。
- abstract,抽象类不能用来实例化对象,声明抽象类是为了将来对该类进行扩充。一个类包含抽象方法,一定要声明为抽象类。一个抽象类可以包含抽象方法和非抽象方法。抽象方法是没有任何实现的方法,该方法的具体实现由子类提供。 任何继承抽象类的子类必须实现父类的所有抽象方法。
- synchronized,被该关键字修饰的方法同一时间只能被一个线程访问。
- transient,序列化对象中包含transient修饰的变量,该变量不会被持久化。
- volatile,被该关键字修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,以强制线程将变化值回写到共享内存。因此,在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
#
6. Java运算符
- 算术运算符(+,-,*,/,%,++,--)
- 关系运算符(==,!=,>,<,>=,<=)
- 逻辑运算符(&&,||,!)
- 条件运算符(三元运算符)
variable x = (expression) ? value if true : value if false
- instance of运算符,检查对象是否是一个特定类型。
( Object reference variable ) instanceof (class/interface type)
#
7. java循环结构
while循环
while( 布尔表达式 ) {
//循环内容
}
do-while循环
do {
//代码语句
}while(布尔表达式);
for循环
for(初始化; 布尔表达式; 更新) {
//代码语句
}
增强for循环
for(循环变量声明语句 : 集合对象)
{
//代码句子
}
#
8. java条件语句
if-else
if(布尔表达式){
//如果布尔表达式的值为true
}else{
//如果布尔表达式的值为false
}
if-else if-esle
if(布尔表达式 1){
//如果布尔表达式 1的值为true执行代码
}else if(布尔表达式 2){
//如果布尔表达式 2的值为true执行代码
}else if(布尔表达式 3){
//如果布尔表达式 3的值为true执行代码
}else {
//如果以上布尔表达式都不为true执行代码
}
#
9. switch case语句
switch(expression){
case value :
//语句
break; //可选
case value :
//语句
break; //可选
//你可以有任意数量的case语句
default : //可选
//语句
}
#
10.java Number类
所有包装类(Interger,Long,Byte,Double,Float,Short)都是抽象类Number的子类。
基本数据类型的强制类型转换
int x = 10;
System.out.println((double)x);
=> 10.0
包装类的类型转换,使用.xxxValue()
函数
Double num = 1234.56; // 实际是Double类型
System.out.println(num.intValue()); // 1234 (截断小数)
System.out.println(num.longValue()); // 1234
System.out.println(num.floatValue()); // 1234.56
#
11.java String类
String创建的字符串存储在公共池(常量池)中,而new创建的字符串对象在堆上。
String s1 = "Runoob"; //常量池
String s4 = new String("Runoob"); //堆
String类是不可变的,一旦创建,它的值就无法改变了。要做修改,可使用StringBuffer或StringBuilder类。
StringBuffer和StringBuilder类的对象能被多次修改,并且不产生新的未使用的对象。StringBuffer是线程安全的,StringBuilder不是线程安全的,但是StringBuilder有速度优势。
.length()
返回字符串长度
string1.concat(string2);
连接两个字符串,也可以直接使用+来连接字符串。
#
12. java数组
声明数组
dataType[] arrayRefVar;
创建数组
arrayRefVar = new dataType[arraySize];
声明和创建
dataType[] arrayRefVar = new dataType[arraySize];
dataType[] arrayRefVar = {value0, value1, ..., valuek};
数组索引从0开始。
多维数组(二维数组为例)
type[][] typeName = new type[typeLength1][typeLength2];
#
13.java方法
方法的定义
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
可变参数
声明方式
typeName... parameterName
一个方法只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
public class VarargsDemo {
public static void main(String[] args) {
// 调用可变参数的方法
printMax(34, 3, 3, 2, 56.5);
printMax(new double[]{1, 2, 3});
}
public static void printMax( double... numbers) {
if (numbers.length == 0) {
System.out.println("No argument passed");
return;
}
double result = numbers[0];
for (int i = 1; i < numbers.length; i++){
if (numbers[i] > result) {
result = numbers[i];
}
}
System.out.println("The max value is " + result);
}
}
#
14.java异常
try-catch
try
{
// 程序代码
}catch(ExceptionName e1)
{
//Catch 块
}
多重捕获
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型3 异常的变量名3){
// 程序代码
}
多异常合并捕获,可以用一个 catch 块处理多个无继承关系的异常。
try {
// 可能抛出多个不同类型异常的代码
} catch (异常类型1 | 异常类型2 | 异常类型3 异常变量) {
// 统一处理
}
throw 关键字用于在代码中抛出异常,而 throws 关键字用于在方法声明中指定可能会抛出的异常类型。
try-with-resource
- try-with-resources 是一种异常处理机制,它能够自动关闭在 try 块中声明的资源,无需显式地在 finally 块中关闭。
- 在 try-with-resources 语句中,只需要在 try 关键字后面声明资源,然后跟随一个代码块。无论代码块中的操作是否成功,资源都会在 try 代码块执行完毕后自动关闭。
try (resource declaration) {
// 使用的资源
} catch (ExceptionType e1) {
// 异常块
}
可以声明多个资源,使用;
分隔每个资源。
#
15.java继承
继承的关系是“is-a”,父类更通用,子类更具体。
class 父类 {
}
class 子类 extends 父类 {
}
- super关键字:实现对父类成员的访问,用来引用当前对象的父类。
- this关键字:指向自己的引用,引用当前对象,即它所在方法或构造函数所属的对象实例。
- 子类不继承父类的构造器,只是调用。如果父类的构造器带参数,必须在子类的构造器中显式的通过super关键字调用父类的构造器并配以适当的参数列表。
#
16.重写和重载
重写是指子类定义了一个与其父类中具有相同名称、参数列表和返回类型的方法,并且子类方法的实现覆盖了父类方法的实现。 即外壳不变,核心重写!
重写的规则:
- 参数列表与被重写方法的参数列表必须完全相同。
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的子类。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
- 父类的成员方法只能被它的子类重写。
- 声明为 final 的方法不能被重写。
- 声明为 static 的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个类,则不能重写该类的方法。 重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
重载的规则:
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。
#
17.java抽象类
- 抽象类除了不能实例化对象之外,类的其他功能依然存在,成员变量,成员方法和构造方法的访问方式和普通类一样。抽象类不能实例化对象,所以抽象类必须被继承。
- 抽象方法只包含方法名,没有方法体。该方法的具体实现由他的子类确定。
- 声明抽象方法会造成下面两个结果:
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
#
18.java接口
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就声明为抽象类。
接口与类的相似点:
- 一个接口可以有多个方法。
- 接口文件保存在.java结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在.class结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。 接口与类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法,Java 8 之后 接口中可以使用 default 关键字修饰的非抽象方法。可以有静态方法和方法体。允许有私有方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。 接口的特性:
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。 接口和抽象类的区别:
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。(java 8之后,接口中可以有静态方法,默认方法和私有方法)。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
接口的声明:
[可见度] interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
#
19.java枚举
枚举一般表示一组常量。
values()
返回枚举类中的所有值ordinal()
找到每个枚举常量的索引valueOf()
返回指定字符串值的枚举常量。
#
20.java集合
ArrayList可动态修改的数组,没有固定大小的限制,可以添加或删除元素。
import java.util.ArrayList; // 引入 ArrayList 类
ArrayList<E> objectName =new ArrayList<>(); // 初始化
add()
添加元素get()
访问元素set()
修改元素remove()
删除元素size()
计算大小 LinkedList可在开头,结尾或中间插入和添加元素
// 引入 LinkedList 类
import java.util.LinkedList;
LinkedList<E> list = new LinkedList<E>(); // 普通创建方法
或者
LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表
HashSet,无序集合,不允许有重复元素,不是线程安全。
import java.util.HashSet; // 引入 HashSet 类
HashSet<String> sites = new HashSet<String>();
add()
添加元素contains()
判断元素是否存在remove()
删除元素clear()
删除集合中所有元素size()
计算大小 *HashMap,存储key-value键值对,允许key为null,不支持线程同步,无序。
import java.util.HashMap; // 引入 HashMap 类
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
put()
添加元素get(key)
获取key对应的valueremove(key)
删除key对应的valueclear()
删除所有元素size()
计算大小
Iterator迭代器,用于遍历集合。只能从前往后遍历集合的元素,不能往回遍历。
#
21.java泛型
泛型方法,在调用时可以接收不同类型的参数。 定义泛型方法的规则:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的
<E>
)。 - 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像 int、double、char 等)。
java 中泛型标记符:
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
public class GenericMethodTest
{
// 泛型方法 printArray
public static < E > void printArray( E[] inputArray )
{
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
public static void main( String args[] )
{
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "整型数组元素为:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
printArray( charArray ); // 传递一个字符型数组
}
}
有界的类型参数,声明一个有界类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
public class MaximumTest
{
// 比较三个值并返回最大值
public static <T extends Comparable<T>> T maximum(T x, T y, T z)
{
T max = x; // 假设x是初始最大值
if ( y.compareTo( max ) > 0 ){
max = y; //y 更大
}
if ( z.compareTo( max ) > 0 ){
max = z; // 现在 z 更大
}
return max; // 返回最大对象
}
public static void main( String args[] )
{
System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",
3, 4, 5, maximum( 3, 4, 5 ) );
System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",
6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",
"apple", "orange", maximum( "pear", "apple", "orange" ) );
}
}
泛型类,声明方式和普通类类似,要在类名后添加类型参数声明部分。
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("菜鸟教程"));
System.out.printf("整型值为 :%d\n\n", integerBox.get());
System.out.printf("字符串为 :%s\n", stringBox.get());
}
}