Java
创建文件名需要和类名一样
1
2
3
4
5
public class Hello{
public static void main(String[] args){
System.out.print("hello world");
}
}
String args[] 与 String[] args 都可以执行,但推荐使用 String[] args,这样可以避免歧义和误读
javac后面跟的是文件名,例如hello.java,该命令用于将java源文件编译成class字节码文件。再执行完javac命令后,如果编译没有出错的话,会出现hello.class文件,就可以用java对该类文件进行运行,这个时候文件名后不加 .java。
java特型
- 面向对象:提供类,接口,继承等特性。只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制。
- 可移植性:任意一个java程序,不管在何种CPU、操作系统都将产生同样的结果。java编译器产生的目标代码是针对一种并不存在的cpu-java虚拟机,可以掩盖不同cpu之间的差别
- 多线程:由Thread类或其子类来创建,通常有两种方法来创建线程:其一,使用型构为 Thread(Runnable) 的构造子类将一个实现了 Runnable 接口的对象包装成一个线程,其二,从 Thread 类派生出子类并重写 run 方法,使用该子类创建的对象即为线程。
基础语法
类名:对于所有类来说,类名的首字母应该大写
方法名:所有方法名都应该以小写字母开头
源文件名:源文件名必须和类名相同。
主方法入口:所有java程序都应该用public static void main(String[] args)方法开始执行
java修饰符用于修饰类的方法和属性:
- 访问控制修饰符:default、public、protected、private
- 非访问控制修饰符:final、abstract、static、synchronized
继承:在java中,一个类可以由其他类派生。如果你要创建一个类,而且已经存在一个类具有你所需要的属性或方法,那么你可以将新创建的类继承该类。利用继承的方法,可以重用已存在类的方法和属性,而不用重写这些代码,被继承的类被称为超类,派生类称为子类。
java源程序与编译型运行区别:
java对象和类
类:类是一个模板,描述一类对象的行为和状态
对象:是类的一个实例,有状态和行为
一个类可以包含以下变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁(无初始值)
- 成员变量:成员变量是定义在类中、方法体之外的变量。这种变量在创建对象时实例化,成员变量可以被类中方法、构造方法和特定类的语句块访问(如果没有定义,有默认初始值)
- 类变量:类变量申明在类中,方法体之外的变量,需要用static声明,实质上是一个全局变量
不同对象的实例变量会分配到不同的位置,但所有对象相同的类变量分配的是同一个位置,对象共享类变量
在一个类中,局部变量可以和成员变量同名,但局部变量优先,如果要调用成员变量则需要使用this关键字
成员变量和类变量的区别:
- 生命周期不同,成员变量随对象消失而消失,类变量随类的消失而消失
- 成员变量只能被对象调用,而类变量可以被对象调用也可被类调用
- 存储位置不同,成员变量是对象特有数据,类变量是对象共享数据
static弊端:
- 有些数据是对象独有数据,所以不能被静态修饰
- 静态方法只能访问静态变量,不能访问非静态变量(可以在方法里面实例化对象来调用实例变量)
- 静态方法不能使用this、super关键字(因为this代表对象,而有可能没有对象)
构造方法:
每个类都有构造方法,如果没有显式地类定义构造方法,则java编译器会自动为该类提供一个默认的构造方法
在创建一个对象的时候,至少要调用一个构造方法;构造方法的名称必须和类名同名,一个类可以有多个构造方法
1
2
3
4
5
6
public class Puppy{
public Puppy(){
}
public Puppy(String name){
}
}
对象:
创建对象包括下面三个步骤:
- 声明:声明一个对象,包括对象名称和对象类型
- 实例化:使用关键字new来创建一个对象
- 初始化:使用new创建对象时,会调用构造函数初始化对象
1
2
3
4
5
6
7
8
public class Puppy{
public Puppy(String name){
System.out.print("name");
}
public static void main(String[] args){
Puppy mp=new Puppy("tim");
}
}
上面程序会输出tim,说明定义对象时,会执行构造函数里的内容
通过已创建的对象来访问成员变量和成员方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Puppy{
int puppyage;
public Puppy(String name){
System.out.println(name);
}
public void setage(int age){
puppyage=age;
}
public int getage(){
return puppyage;
}
public static void main(Stirng[] args){
puppy py=new puppy("tim");
py.steage(20);
py.getage();
}
}
源文件声明规则:
- 一个源文件只能有一个public类
- 一个源文件可以有多个非public类
- 源文件名称应该和public类的类型保持一致
- 如果一个类定义在某个包里面,那么package语句应该放在源文件首行
- 源文件中import语句应该放在package语句和类定义之间
内部类:
java中一个类可以嵌套另一个类,其语法格式为:
1
2
3
4
5
class Outerclass{ //外部类
class nestedclass{ //嵌套类或者内部类
}
}
访问内部类,可以通过创建外部类对象,然后创建内部类的对象来实现
内部类(嵌套类)有两种类型:
-
非静态内部类
一个类中嵌套着另外一个类。有访问外部类成员的权限,称为内部类
需要先实例化外部类,再创建内部类的对象来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class Outerclass{ //外部类 int x=10; class Innerclass{ //嵌套类或者内部类 int y=5; } } public class Mainclass{ public static void main(String[] args){ Outerclass myouter=new Outerclass(); Outerclass.Innerclass myinner=myouter.new Innerclass();//创建内部类对象 System.out.println(myouter.x+myinner.y); } }
内部类的一个高级用法就是可以访问外部类的属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class Outer{ int x=10; class Inner{ public int myinnerMethod(){ return x; } } } public class Mainclass{ public static void main(String[] args){ Outer myouter =new Outer(); Outer.Inner myinner=myouter.new Inner(); System.out.println(myinner.myinnerMethod()); } }
内部类可以用private或protected来修饰,如果不希望内部类被外部类访问可以用private修饰符
1 2 3 4 5 6 7 8 9 10 11 12 13
class Outer{ int x=10; private class inner{ int y=10; } } public class Mainclass{ public static void main(String[] args){ Outer myouter=new Outer(); Outer.inner myinner=myouter.new inner(); System.out.print(myouter.x+myinner.y); } }
运行结果:
-
静态内部类
静态内部类可以用static关键字定义,静态内部类不需要创建外部类来访问,可以直接访问
1 2 3 4 5 6 7 8 9 10 11 12
class Outer{ int x=5; static class Inner{ int y=10; } } public class Mainclass{ public static void main(String[] args){ Outer.Inner myinner=new Outer.Inner(); //直接实例化内部类 System.out.print(myinner.y); } }
静态类不能访问外部类成员
匿名类:
java可以实现一个类中包含另一个类,且不需要类名直接实例化
主要用于在我们需要的时候创建一个对象来执行特定的任务,可使代码更加简洁
匿名类和内部类不同,匿名类没有类名,不能被引用,只能创建时用new语句来进行申明
1
2
3
4
5
6
class Outer{
//定义一个匿名类
object1=new Type(parameterlist){
//匿名类代码
};
}
匿名类通常继承一个父类或者实现一个接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Polygon{ //匿名类的要继承的父类
public void display(){
System.out.println("在Polygon里");
}
}
class AnonymousDemo{
public void createClass(){ //创建一个方法方便调用
Polygon p1=new Polygon(){
public void display(){ //改写display方法
System.out.println("在匿名类里");
}
};
p1.display();
}
}
public class Mainclass{
public static void main(String[] args){
AnonymousDemo an=new AnonymousDemo();
an.createClass(); //最后输出:"在匿名类里"
}
}
使用创建的匿名类实现接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Polygon{
public void display();
}
public class Mainclass{
public static void main(String[] args){
Polygon p1=new Polygon(){
public void display(){
System.out.println("匿名类继承接口");
}
};
p1.display();
}
}
import语句
如果给出一个完整的限定名,包括包名,类名,那么java编译器就可以容易定位到源代码或者类中,import语句可以提供一个合理的路径,使编译器能够找到某个类。
通过package和import都可以跨文件调用类
package :就是 c++ 的 namespace 的作用,防止名字相同的类产生冲突。Java 编译器在编译时,直接根据 package 指定的信息直接将生成的 class 文件生成到对应目录下。如 package aaa.bbb.ccc 编译器就将该 .java 文件下的各个类生成到 ./aaa/bbb/ccc/ 这个目录。
import :为了简化使用 package 之后的实例化的代码。假设 ./aaa/bbb/ccc/ 下的 A 类,假如没有 import,实例化A类为:new aaa.bbb.ccc.A(),使用 import aaa.bbb.ccc.A 后,就可以直接使用 new A() 了,也就是编译器匹配并扩展了 aaa.bbb.ccc. 这串字符串。
基础数据类型
java两大数据类型:
-
内置数据类型
byte(8位,有符号)、short(16位,有符号)、int(32位,有符号)、long(64位,有符号)、float(32位)、double(64位)、bool、char
使用long类型的数据一定要在数值后面加上L,否则遇到大的数据时会报错溢出
1
long a=123553154351531L;
可以通过封装的函数知道一个类型的信息
1 2 3 4 5 6 7
public class Mainclass{ public static void main(String[] args){ System.out.println(Integer.SIZE); //二进制位数 System.out.println(Integer.MAX_VALUE);//最大值 System.out.println(Integer.MIN_VALUE);//最小值 } }
-
引用数据类型
类似于c++的指针,引用类型指向一个对象,指向对象的变量是引用变量。变量一旦声明,类型变不能改变
对象、数组都是引用数据类型
所有引用类型的默认值都是null
java常量
常量在程序运行时是不能被修改的,用final来修饰常量
1
final double PI=3.14;
使用字面量的时候,前缀0表示8进制,前缀0x代表16进制
java也支持整形、实型、字符型数据混合运算。运算中,不同类型的数据先转化为同一数据类型,再进行计算
由低级到高级自动转化
1
2
3
低 ------------------------------------> 高
byte,short,char—> int —> long—> float —> double
且满足如下规则:
-
不能对bool类型进行转换
-
不能把数据类型转化成不相关的对象
-
大容量转化为小容量是必须要强制转化,但可能造成溢出
1 2
int i=128; byte b=byte(i); //byte类型最大值为127,所以导致溢出
-
浮点类型转化为整数通过舍弃小数部分完成,而不是四舍五入
字符串和其他类型的转化:
-
其他类型转化为String:1.调用类的串转化方法:X.toString();2.String.valueOf(X)
-
String转化成其他类型:
1.先转化为相应封装器实例,再调用对应方法转化为其他类型,例:Double.valueOf(“32.1”).doubleValue()
2.静态parse方法
1 2 3 4 5 6 7
String s = "1"; byte b = Byte.parseByte( s ); short t = Short.parseShort( s ); int i = Integer.parseInt( s ); long l = Long.parseLong( s ); Float f = Float.parseFloat( s ); Double d = Double.parseDouble( s );
在java中,任何字符类型和字符串相加,结果都是拼接
1
2
3
String s = null;
s += "hello";
System.out.println(s); // 输出 nullhello
原因:编译器会先应用 String.valueOf 得出 s 的 value 值,再通过 StringBuilder 拼接 hello,因此将 value 与 hello 进行了拼接。
1
2
3
String s = null;
s = (new StringBuilder(String.valueOf(s))).append("hello").toString();
System.out.println(s);
java变量类型
java局部变量
- 访问修饰符不能用于局部变量
- 局部变量是栈上分配
- 局部变量没有默认值
实例变量
-
当一个对象被实例化后,每个实例变量的值就跟着确定
-
实例变量的值至少被一个方法、构造函数、语句块引用,使得外部能够通过这些方法获取实例变量的信息
-
可以声明在使用前或者使用后
-
如果把实例变量设置为private类型,在其他类中不能直接调用,可以通过调用实例化对象的方法来进行调用
1 2 3 4 5 6 7 8 9 10 11 12
class a{ private int aa=10; public void b(){ System.out.println(aa); } } public class Mainclass{ public static void main(String[] args) { a a1=new a(); a1.b(); //通过方法来调用private类型的成员变量 } }
类变量
- 无论一个类创建了多少对象,类只拥有类变量的拷贝
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用 static 声明变量
- 类变量被声明为 public static final 类型时,类变量名称一般建议使用大写字母。如果静态变量不是 public 和 final 类型,其命名方式与实例变量以及局部变量的命名方式一致
同一个类中,static方法只能调用static方法和static变量,不能调用非static方法,但非static都可以调用
java修饰符
访问控制修饰符:
- default:适用对象为类、接口、方法、变量
- private:在同一类中可见。适用对象为方法、变量
- public:对所有类看见。适用对象为类、接口、变量、方法
- protected:对同一包内的类和所有子类可见。适用对象为方法、变量
访问控制与继承
- 父类中声明为public的方法在子类中也必须为public
- 父类中声明为protected的方法在子类中可以声明为public和protected,但不能声明为private
- 父类中声明为 private 的方法,不能够被继承
非控制修饰符:
static 修饰符:用来修饰类方法和类变量。
final 修饰符:用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
abstract 修饰符:用来创建抽象类和抽象方法。
抽象类不能用于实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充,所以不能同时用abstract和final修饰一个类
抽象类中可以包含抽象方法(由子类实现)和非抽象方法,任何继承抽象类的子类必须实现父类的所有抽象方法,除非其也是抽象类
abstract不能和static一起修饰,因为static不能被子类覆盖,而abstract需要被继承实现
synchronized 和 volatile 修饰符:主要用于线程的编程。
java运算符
位运算符
1
2
3
4
5
6
7
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A= 1100 0011
C + = A 与 C = C + A 是有区别的一句话总结: += 运算符既可以实现运算,又不会更改 s 的数据类型;而后者,C 和 A 必须是同一类型,否则无法直接运算。
条件运算符
三元运算符,有三个操作数,需要判断布尔表达式的值
1
variable x = (expression) ? value if true : value if false: value
instanceof运算符
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)
1
2
String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Vehicle {}
public class Car extends Vehicle {
public static void main(String args[]){
Vehicle v1 = new Vehicle(); //父类型
Vehicle v2 = new Car(); //子类的实例可以声明为父类型
Car c1 = new Car(); // 子类型
Car c2 = new Vehicle(); //这句会报错,父类型的实例不能声明为子类型
//Car(子类)是Vehicle(父类)类型, Vehicle(父类)不是Car(子类)类型
boolean result1 = c1 instanceof Vehicle; // true
boolean result2 = c1 instanceof Car; // true
boolean result3 = v1 instanceof Vehicle; // true
boolean result4 = v1 instanceof Car; // false
boolean result5 = v2 instanceof Vehicle; // true
boolean result6 = v2 instanceof Car; // true
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
System.out.println(result4);
System.out.println(result5);
System.out.println(result6);
}
}
java循环结构
-
while
1 2 3
while( 布尔表达式 ) { //循环内容 }
-
do…..while
1 2 3
do { //代码语句 }while(布尔表达式);
-
for
1 2 3
for(初始化; 布尔表达式; 更新) { //代码语句 }
break、continue
java条件语句
java switch case语句
1
2
3
4
5
6
7
8
9
10
11
switch(expression){
case value :
//语句
break; //可选
case value :
//语句
break; //可选
//你可以有任意数量的case语句
default : //可选
//语句
}
Number&Math方法
函数名 | 函数具体描述 |
---|---|
xxxValue(): | 将对象以xxx数据类型返回,例如x.byteValue() |
x.compareTo(3) | x与3进行大小比较,相等返回0,大于返回1,否则-1 |
x.equals(y) | 比较x与y是否相等 |
xxx.valueOf(x) | 将x转化为xxx数据类型 |
…. | …. |
java character类
用于对单个字符进行操作
将一个char类型的参数传递给需要一个Character类型参数的方法时,那么编译器会自动地将char类型参数转换为Character对象。 这种特征称为装箱,反过来称为拆箱
转义序列
\t | 在文中该处插入一个tab键 |
---|---|
\b | 在文中该处插入一个后退键 |
\n | 在文中该处换行 |
\r | 在文中该处插入回车 |
\f | 在文中该处插入换页符 |
' | 在文中该处插入单引号 |
" | 在文中该处插入双引号 |
\ | 在文中该处插入反斜杠 |
java string类
创建字符
- String str = “Runoob”; 存储在公共池中
- String str2=new String(“Runoob”); 存储在堆上
string类是不可改变的,创建string对象后,其值便无法改变
如果需要对字符进行改变,那么应该选择使用StringBufffer和StringBuilder类
连接字符串
-
string1.concat(string2);
-
使用’+‘操作符来连接字符串
concat是通过复制数组在通过char数组进行拼接生成一个新的对象,所以地址会发生变动
1 2 3 4 5
String s11="a"+"b"+"c"; String s22="abc"; String s33="a".concat("b").concat("c"); System.out.println(s22==s11); //true System.out.println(s22==s33); //false
创建格式化字符串
-
使用format()
使用format返回一个String对象,即可复用的格式化字符串
1 2 3 4 5 6
String fs; fs = String.format("浮点型变量的值为 " + "%f, 整型变量的值为 " + " %d, 字符串变量的值为 " + " %s", floatVar, intVar, stringVar);
-
使用printf()
关于String对象不可变
1
2
String s = "Google";
s = "Runoob";
上例中s只是String对象的一个引用,并不是对象本身,当执行s = “Runoob”是创建了一个新的对象,而原来的”Google“还在内存中
’==‘是判断字符串地址,equals是判断字符串内容
1
2
3
4
5
6
7
8
9
String a = "saff";
String b = "saff";
String c = new String("saff");
String d=a;
System.out.println(a.equals(b)); // true
System.out.println(a.equals(c)); // true
System.out.println(a==b); //true
System.out.println(a==c); //false
System.out.println(a==d); //true
对于a和b来说,最开始创建了一个a,在内存中开辟一块内存,在创建b的时候在内存中找到了一样的字符,所以将b指向这块内存的地址,所以a和b的地址和内容都是一样的,对于c来说,用new创建的,所以会在堆中新创建一块地址,所以a和c地址不同,内容相同。对于d来说也是直接在内存中指向之前创建的地址。
同理,即便是拼接字符串,如果内容一样,地址也是一样的。s1拼接好后去内存中寻找,找到一样的字符串后就直接指向
1
2
3
4
String s1="a"+"b"+"c";
String s2="abc";
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
特例
1
2
3
4
String s1="ab";
String s2="abc";
String s3=s1+"c";
System.out.println(s3==s2); // false
首先在内存中创建s1和s2,在创建s3的时候,先创建StringBuilder对象,然后通过append连接得到abc,再调用toString()转换的地址指向s3,所以地址不同
String Buffer和String Builder
它们之间的区别如下:
- 线程安全性:StringBuffer是线程安全的类,因为它的所有公共方法都被synchronized修饰,所以在多线程环境下,它可以保证多个线程对字符串的访问是同步的。而StringBuilder是非线程安全的类,因为它的所有公共方法都没有被synchronized修饰,所以在多线程环境下,如果多个线程同时访问一个StringBuilder对象,就有可能出现竞争条件,导致数据不一致或错误的结果。
- 性能:由于StringBuffer的所有公共方法都是同步的,所以在多线程环境下,它的性能会受到影响。而StringBuilder的所有公共方法都没有被同步,所以在单线程环境下,它的性能会比StringBuffer更好。
- API支持:StringBuilder是JDK 1.5引入的新类,而StringBuffer则早在JDK 1.0就已经存在。虽然两者都提供了类似的API,但是StringBuilder还提供了一些新的API,如reverse()方法。
因此,如果在单线程环境下处理字符串,建议使用StringBuilder,因为它具有更好的性能。而在多**】线程环境下,或者需要在不同的线程中共享一个可变的字符串对象时,建议使用StringBuffer,因为它是线程安全的。
java数组
申明数组
1
dataType[] arrayRefVar;
创建数组
1
arrayRefVar = new dataType[arraySize];
Arrays类相关方法:
fill函数对数组进行赋值
1
Arrays.fill(array, 5);
sort函数对数组进行排序
1
Arrays.sort(array1, 2, 7);
equals函数判断数组是否相等
1
Arrays.sort(array1, 2, 7);
clone函数对数组进行克隆
1
int[] array2 = array1.clone();
多维数组
1
type[][] typeName = new type[typeLength1][typeLength2];
1
2
3
4
5
6
7
8
String[][] s = new String[2][];
s[0] = new String[2];
s[1] = new String[3];
s[0][0] = new String("Good");
s[0][1] = new String("Luck");
s[1][0] = new String("to");
s[1][1] = new String("you");
s[1][2] = new String("!");
字符和数组之间的转化
1
2
String str = "helloworld";
char[] data = str.toCharArray();// 将字符串转为数组
java 日期时间
Date date=new Date();
Java使用以下三种方法来比较两个日期:
- 使用 getTime() 方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值。
- 使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回true。
- 使用 compareTo() 方法,它是由 Comparable 接口定义的,Date 类实现了这个接口。
java休眠(sleep)
sleep()使当前线程进入停滞状态,让出cpu,留一定时间给其他线程
正则表达式
java.util.regex 包主要包括以下三个类:
-
Pattern 类:
pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
-
Matcher 类:
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
-
PatternSyntaxException:
PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
1
2
3
String content = "I am noob " + "from runoob.com.";
String pattern = ".*runoob.*";
boolean isMatch = Pattern.matches(pattern, content);
方法
方法重载
一个类的两个方法拥有相同的名字,但是有不同的参数列表
可变参数
typeName… parameterName
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明
一个函数至多只能有一个可变参数,且可变参数为最后一个参数。对于可变参数,编译器会将其转型为一个数组,故在函数内部,可变参数名即可看作数组名。
finalize()方法
在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象
可以使用 finalize() 来确保一个对象打开的文件被关闭了
java流、文件、IO
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
读取控制台输入
为了获得一个绑定到控制台的字符流,你可以把 System.in 包装在一个 BufferedReader 对象中来创建一个字符流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
然后利用read() 方法从控制台读取一个字符,或者用 readLine() 方法读取一个字符串
FileInputStream
从文件中读取数据
- InputStream f = new FileInputStream(“C:/java/hello”);
- File f = new File(“C:/java/hello”); InputStream in = new FileInputStream(f);
序号 | 方法及描述 |
---|---|
1 | public void close() throws IOException{} 关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常。 |
2 | protected void finalize()throws IOException {} 这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常。 |
3 | public int read(int r)throws IOException{} 这个方法从 InputStream 对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回-1。 |
4 | public int read(byte[] r) throws IOException{} 这个方法从输入流读取r.length长度的字节。返回读取的字节数。如果是文件结尾则返回-1。 |
5 | public int available() throws IOException{} 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值。 |
FileOutputStream
创建一个文件并向文件中写数据
- OutputStream f = new FileOutputStream(“C:/java/hello”)
- File f = new File(“C:/java/hello”); OutputStream fOut = new FileOutputStream(f);
序号 | 方法及描述 |
---|---|
1 | public void close() throws IOException{} 关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常。 |
2 | protected void finalize()throws IOException {} 这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常。 |
3 | public void write(int w)throws IOException{} 这个方法把指定的字节写到输出流中。 |
4 | public void write(byte[] w) 把指定数组中w.length长度的字节写到OutputStream中。 |
java创建目录
File类中有两个方法可以用来创建文件夹:
- mkdir( )方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
- mkdirs()方法创建一个文件夹和它的所有父文件夹。
1
2
3
4
String dirname = "/tmp/user/java/bin";
File d = new File(dirname);
// 现在创建目录
d.mkdirs();
读取目录
一个目录其实就是一个 File 对象,它包含其他文件和文件夹。
如果创建一个 File 对象并且它是一个目录,那么调用 isDirectory() 方法会返回 true。
可以通过调用该对象上的 list() 方法,来提取它包含的文件和文件夹的列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (f1.isDirectory()) {
System.out.println("目录 " + dirname);
String s[] = f1.list();
for (int i = 0; i < s.length; i++) {
File f = new File(dirname + "/" + s[i]);
if (f.isDirectory()) {
System.out.println(s[i] + " 是一个目录");
}
else {
System.out.println(s[i] + " 是一个文件");
}
}
}
else {
System.out.println(dirname + " 不是一个目录");
}
使用java.io.File.delete() 删除文件
java scanner类
1
Scanner sc=new Scanner(System.in);
使用next()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Scanner;
public class Mainclass{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
System.out.println("Next方式接收:");
if(sc.hasNext()){
String s=sc.next();
System.out.println(s);
}
sc.close();
}
}
使用nextline()方法
接受一行的数据
next() 与 nextLine() 区别
next():
- 1、一定要读取到有效字符后才可以结束输入。
- 2、对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
- 3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
- next() 不能得到带有空格的字符串。
nextLine():
- 1、以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
- 2、可以获得空白。
Scanner有专门支持int,float类型的函数,可以先用hasNextXXX()来进行验证,再读取
Console类可以用于读取密码
1
2
3
Console cons = System.console();
String username = cons.readLine("name:");
char[] passwd = cons.readPassword("Password: ");
使用StringTokenizer类可以自动分割语句
1
2
3
4
5
6
7
8
9
public class Mainclass{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
StringTokenizer st=new StringTokenizer(sc.nextLine());
while(st.hasMoreTokens()){
System.out.println(st.nextToken());
}
}
}
Scanner类读取文件
1
Scanner sc=new Scanner(new File("test.txt"));
java异常处理
- 用户输入数据非法
- 要打开的文件不存在
- 网络通信时中断,或者JVM内存溢出
Exception类层次
Exception是Throwable类的子类
异常类有两个主要的子类:IOException 类和 RuntimeException 类
异常方法:
序号 | 方法及说明 |
---|---|
1 | public String getMessage() 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 |
2 | public Throwable getCause() 返回一个Throwable 对象代表异常原因。 |
3 | public String toString() 使用getMessage()的结果返回类的串级名字。 |
4 | public void printStackTrace() 打印toString()结果和栈层次到System.err,即错误输出流。 |
5 | public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 |
6 | public Throwable fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 |
通常使用try…catch…来捕获异常
1
2
3
4
5
try{
// 程序代码
}catch(ExceptionName e1){
//Catch 块
}
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查
多重捕获块(一个try后面跟着多个catch代码块的情况)
1
2
3
4
5
6
7
8
9
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型3 异常的变量名3){
// 程序代码
}
throws/throw关键字
区别:throws表示一个方法声明可能抛出一个异常,throw表示此处抛出一个已定义的异常(可以是自定义需继承Exception,也可以是java自己给出的异常类)
如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。
也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
1
2
3
4
5
6
7
8
9
10
import java.io.*;
public class className
{
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException
{
// Method implementation
}
//Remainder of class definition
}
finally
用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally 代码块中的代码总会被执行。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
注意下面事项:
- catch 不能独立于 try 存在。
- 在 try/catch 后面添加 finally 块并非强制性要求的。
- try 代码后不能既没 catch 块也没 finally 块。
- try, catch, finally 块之间不能添加任何代码。
可以自定义异常类
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承:通过创建父类的方式,解决代码大量重复,臃肿的问题
继承特性
- 子类拥有父类非 private 的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
可以用extends和implements关键字实现继承
extends
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Animals{
private String name;
private int id;
public Animals(String myName,String myid){
}
public void eat(){
}
}
class x extends Animals{
}
implements(接口可以多继承)
1
2
3
4
5
6
7
8
9
10
11
12
public interface Mainclass {
public void a();
public void b();
}
interface bb{
public void c();
}
class cc implements Mainclass,bb{
public void a(){}
public void b(){}
public void c(){}
}
super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class animals{
public void eat(){
System.out.println("1");
}
}
class dog extends animals{
public void eat(){
System.out.println("2");
}
public void testeat(){
super.eat();
this.eat();
}
}
构造器
子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。
对于子类的构造函数而言,会默认调用父类的没有参数的构造函数,也可用super调用父类有参数的构造函数,不过要提前赋值
重写与重载
重写:子类对父类允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变
重写的好处在于可以根据自己的情况来对父类方法进行改写
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class d1{
void run(){
System.out.println("1");
}
}
class d2 extends d1{
void run(){
System.out.println("2");
}
}
public class Mainclass{
public static void main(String[] args) {
d1 a=new d1(); //d1对象
d1 b=new d2(); //d2对象
a.run(); //输出1
b.run(); //输出2
}
}
方法的重写规则
- 参数列表与被重写方法的参数列表必须完全相同。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
- 父类的成员方法只能被它的子类重写。
- 声明为 final 的方法不能被重写。
- 声明为 static 的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个类,则不能重写该类的方法。
重载
重载是在一个类中,方法名字相同,而参数不同。
每个重载的方法都有一个独一无二的参数列表
最常见的重载是构造器
重载规则:
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。
区别点 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可以修改 | 一定不能修改 |
异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
重写和重载都是java多态性的不同表现,重写是父类与子类间多态性的表现,重载是多态性的具体表现
构造器
多态
同一个行为具有多个不同表现形式或形态的能力
同一个接口使用不同的实例而进行不同的操作
多态存在的三个条件:
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
多态的好处:首先检查父类中是否存在该方法,如果没有则编译错误,如果有,则调用子类的同名方法。这样使程序具有很好的扩展性,对所有类的对象通用
虚函数
动态绑定是java默认行为,也可以通过final关键字变为非虚函数
多态的实现
- 重写
- 接口
- 抽象类和抽象方法
如果父类的构造函数含有形参,则子类的构造函数需要用super()对其进行赋值
java抽象类
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。但接口不能实现方法
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
抽象方法
该方法的实现由子类确定,便可以在父类中定义该方法为抽象方法
1
public abstract void b();
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
java封装
封装是指将抽象函式接口的实现细节部分包装,隐藏起来的方法
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段
封装的步骤:
- 修改属性的可见性来限制对属性的访问
- 对每个值属性提供对外公共访问的方法,即通过公共方法来访问私有变量
java接口
接口,抽象方法的集合,通常以interface来声明,一个类通过继承接口的方式,来继承接口的抽象方法
除非继承接口的类是抽象类,否则该类需定义接口中所有方法
接口与类相似点:
- 一个接口可以有多个方法。
- 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在 .class 结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
接口与类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法,Java 8 之后 接口中可以使用 default 关键字修饰的非抽象方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承
接口的方法都默认public abstract,变量都默认 public static final ,接口的方法都由继承接口的类来实现
所以变量定义必须要赋值
1
2
3
4
[可见度] interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
类通过使用implements关键字来实现接口
1
2
3
class a implements b{
}
类在重写方法时要保持一样的方法名,并有相同或者兼容的返回值类型
接口之间的继承使用extends,子接口继承父接口方法,接口之间允许多继承
标记接口:没有任何方法的接口
主要用于:
- 建立一个公共的父接口
- 向一个类添加数据类型
java枚举
用enum关键字来定义,各常量使用逗号进行分割
1
2
3
4
5
6
7
8
9
enum C{
a,b,c;
}
public class test{
public static void main(String[] args){
C t=C.a;
System.out.println(t);
}
}
相关的方法:
- values() 返回枚举类中所有的值。
- ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
- valueOf()方法返回指定字符串值的枚举常量。
枚举类中的抽象方法实现,需要枚举类中的每个对象都对其进行实现。
java包
包的作用
- 1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
- 2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
- 3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
如果其他的一个源文件包含了这个包提供的类、接口、枚举或者注释类型的时候,都必须将这个包的声明放在这个源文件的开头。
包声明应该在源文件的第一行,每个源文件只能有一个包声明,这个文件中的每个类型都应用于它。
如果一个源文件中没有使用包声明,那么其中的类,函数,枚举,注释等将被放在一个无名的包(unnamed package)中。