public static void main(String[] args) {
int[] i = new int[10];
i[10]= 99;
boolean[] b = new boolean[3];
b = null;
System.out.println(b[0]);
String[] str = new String[4];
System.out.println(str[3].toString());
int[][]j = new int[3][];
j[2][0] = 33;
int[] array1, array2;
array1 = new int[] {
2, 3, 8};
/*
array2 = array1
error:如果修改array2会同时修改1,因为这样只是传递了地址给2
*/
array2 = new int[array1.length];
for (int i = 0; i < array1.length; i++){
array2[i] = array1[i];
}
int[] arr = new int[]{
9, 88, 5};
for(int i = 0;i < arr.length/2;i++){
int temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}//第一种
/*第二种
for(int x = 0,y = arr.length - 1;x < y;x++,y--){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
*/
冒泡
public static void main(String[] args) {
int[]arr = new int[]{
49,343,45,87,3,13,67};
for(int i = 0; i < arr.length -1; i++){
for(int j = 0; j < arr.length -1 - i; j++){
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
System.out.println("从小到大排序以后:");
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i] + "\t");
}
}
直接选择顺序
public static void main(String[] args) {
int[]arr = new int[]{
49,343,45,87,3,13,67};
for(int i = 0; i < arr.length - 1; i++) {
int t = i;//默认i是最小
for(int j = i; j < arr.length; j++) {
//一旦在i后发现存在比i小的元素,记录那个下角标
if(arr[t] > arr[j]) {
t = j;
}
}
if(t != i) {
int temp = arr[t];
arr[t] = arr[i];
arr[i] = temp;
}
}
System.out.println("从小到大排序以后:");
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i] + "\t");}// TODO Auto-generated method stub
}
同一个类中,方法名相同,而参数列表不同(类型/个数),与返回类型无关
class Overload{
public int getSum(int i,int j){
return i + j;
}
public int getSum(int i, int j, int k){
return i + j + k;
}
public int getSum(double a, double b){
return a * b;
}
public void getSum(double a, double b, double c){
System.out.println(a + b + c);
}
}
class Overload{
public void method(int i, String j){
}
public void method(String j, int i){
}
}
创建的类的对象是匿名的
p.printAreas(new Circle(), 6);
//System.out.println(c.getRadius);
// 以下三个sayHello()仍为overload
public void sayHello(String str1){
System.out.println("hello" + str1);
}
public void sayHello(){
for(int i = 0; i < args.length; i++){
System.out.println(args[i]);
}
}
// 可变个数形参
public void sayHello(String... args){
for(int i = 0; i < args.length; i++){
System.out.println(args[i]);
}
}
public void sayHello(int i, String... args){
for(int i = 0; i < args.length; i++){
System.out.println(args[i]);
}
}
pass by value 值传递:
问题: 不让对象直接作用属性,而是通过“方法.属性”来控制对象对属性的访问
public class TestAnimal {
public static void main(String[] args){
Animal a1 = new Animal();
a1.setLegs(4);
a1.setname("花花");
a1.getLegs();
a1.getName;
}
}
class Animal{
private String name;
private int legs;
//private 修饰的属性只能在本类中来调用,出了本类,只能用公共方法来调用
public void setLegs(int l){
if(l > 0 && l % 2 ==0){
legs = l;
}else{
System.out.println("您输入的数据有误");
}
}
public void setName(String n){
//...
name = n;
}
//设置类的属性
public int getLegs(){
return legs;
}
public String getName(){
return name;
}
//获取类的属性
}
修饰符 | 类内部 | 同一个包 | 子类 | 任何地方 |
---|---|---|---|---|
private | yes | |||
(default) | yes | yes | ||
protected | yes | yes | yes | |
public | yes | yes | yes | yes |
class 只能用(default)和 public
前两个是属性(field),方法(method)
作用:
1. 创建对象
2. 给创建的对象的属性赋值
public class TestPerson{
public static void main(String[] args){
//Person p1 = new Person(); 默认的空参
Person p2 = new Person("Jack", 23);
System.out.println(p2.getName);
System.out.println(p2.getAge);// Jack 0
Person p3 = new Person("Rose", 22);
System.out.println(p3.getName + "\t" + p3.getAge); //Rose 22
}
}
class Person{
// 属性
private String name;
private int age;
// 构造器
public Person(String n){
name = n;
}
public Person(int m){
age = m;
}
public Person(String n, int m){
name = n;
age = m;
}
// 方法
public void setName(String n){
name = n;
}
public void setAge(int m){
age = m;
}
public getName(){
return name;
}
public getAge(){
return age;
}
}
类对象的属性赋值先后: 1. 默认初始化 2. 显式 3. 构造器 4. “对象.方法()”
this.当前对象或当前正在创建的对象
可修饰 属性, 方法, 构造器
在构造器中, “this(argument)”: 调用当前类重载的指定构造器
- 在构造器内部必须是首行!
- 若一个类中有n个构造器, 那么最多有 n - 1 个构造器中使用this(argument), 否则会出现环路
class Person{
private int age;
private String name;
public Person(String name){
this.name = name;
}
public Person(int age){
this.age = age;
}
// this.age: 当前正在创建的对象
public Person(int age, String name){
this(age);// 显式的调用当前类的重载的指定构造器
this.name = name;// this(name);
}
public void setAge(int age){
this.age = age;
}
//this.age: 当前对象
public void info(){
System.out.println("age:" + this.age);
this.show();// this.show(): 当前方法
}
public void show(){
System.out.println("我是一个人,我的年龄是:" + this.age);
}
}
声明源文件所在的包, 写在程序的第一行
每**"."**一次, 表示一层文件目录
package study.qinghu.java
小写
显式导入指定包下的类或接口
若导入java.lang包下的,如: System, String, Math, etc, 不用显示声明
“.*”
import java.util.*
同名类的导入, 如: 在util包和sql包下同时存在Date类
import java.util.*
...
Date d = new Date();
java.sql.Date d1 = new java.sql.Date(23423428L);
import static 表示导入指定类的static的属性/方法
只能导入包下的所有类/接口, 不能导入子包下的类或接口
public class Person{
public void eat{
System.out.println("吃饭");
}
}
public class Worker extends Person{
public static void main(String[] args) {
Student s = new Student();
s.eat();
}
}
对父类重名的类进行重写. 修饰符 返回值类型 方法名 (参数列表) { }
public class Worker extends Person{
public void eat() {
System.out.println("工人吃饭");
}
}
原因: 子类继承父类后, 若父类的方法对子类不适用, 那么子类可以对父类的方法覆盖
规则:
当子类与父类有同名的属性时, 可以通过"super.属性" 显式的调用父类中同名的属性; "this.属性"调用子类中同名的属性
当子类重写父类的方法后, "super.方法"在子类中显式调用父类中被重写的方法
在子类中使用"super(形参列表)"来显式的调用父类中指定的构造器
- 在构造器中, "super(形参列表)"必须声明在首行. 所以super和this只能出现其中一个
- 在构造器中, 不显式调用"this(argument)"或"super(argument)"任何一个, 默认调用的是父类空参的构造器
建议: 设计一个类时, 尽量要提供一个空参的构造器
多态性
方法的重载和重写
子类对象的多态性
子类对象的多态性使用前提:
编译和运行
编译时, “看左边”, 将此引用变量理解为父类的类型
运行时, “看右边”, 关注真正的对象的实体: 子类的对象. 执行的方法就是子类重写的.
向下转型:
强转符: Man m1 = (Man) p1;
保证不报错ClassCastException, 最好向下转型前, 进行判断: if (p1 instanceof Woman){ }
子类对象的多态性, 并不适用于属性. 即"看左边"
public class JavaPolymorphism {
public static void main(String[] args) {
...
//子类对象的多态性,父类的引用指向子类对象
Person p1 = new Man();//向上转型
//虚拟方法调用: 通过父类的引用指向子类的对象实体, 实际执行的是子类重写父类的方法
p1.eat();
p1.walk();
//p1.shaving(); 编译不通过, 因为Person类里没有Man类的方法
Man m1 = (Man)p1;//向下转型, 使用强转符
m1.shaving();
// Women w = (Woman)p1;
// w1.shopping;编译通过, 运行报错
//instanceof:返回值boolean
if (p1 instanceof Woman) {
Woman w1 = (Woman)p1;
w1.shopping();
}
if (p1 instanceof man) {
man m1 = (man)p1;
m1.shaving();
}
}
}
equals()
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.equals(p2));//false
System.out.println(p1 == p2);//false
3. String,Package类 ,File类 , Data类 重写Object类的equals()方法, 比较两个对象的"内容"是否完全相同
String str1 = new String("AA");
String str2 = new String("AA");
String str3 = "AA";
String str4 = "AA";
System.out.println(str1 == str2);//false
System.out.println(str1.equals(str2));//true
System.out.println(str3 == str4);// true "AA"在常量池
System.out.println(str1.equals(str3));// true
4. 自定义一个类, 希望比较两个对象的属性值都相同的情况下返回true, 就需要重写equals(Object obj)方法
//自定义
public boolean equals(Object obj){
if (this == obj){
return true;
}
if (obj instanceof Person){
Person p = (Person)obj;
return this.equals(p.name) == p.name && this.age == p.age;
} else {
return false;
}
}
== :
- primitive: 比较值
- reference: 比较地址值
java.lang.Object.toString:
public String toString() {
return getClass().getName() + "@" + Interger.toHexString(hashCode());
}
当打印一个对象的引用时, 默认调用的是这个对象的toString()方法
当打印的对象所在类没有重写Object中toString()时, 那么调用的是Object定义的返回对象所在的类及对应的堆空间对象的首地址值
常常如下重写了toString(), 将对象的属性信息返回
public String toString() {
return "Person: name = " + name + " age= " + age;
}//手动
//自动
String, Wrapper, File, Data, 已经实现了Object中toString() override
Primitive | Wrapper |
---|---|
boolean | Boolean |
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
- Wrapper 默认null
- autoboxing/ unboxing
Wrapper与Primitive, String相互转化
@Test
public void test2() {
//Primitive, Wrapper ---> String:
int i1 = 10;
String str1 = i1 + "";//"10" 方法1
Integer i2 = i1;
String str2 = String.valueOf(i2);//方法2: 调用String override的valueOf(Xxx x)方法
String str3 = String.valueOf(true);
//String--->Primitive, Wrapper:
int i3 = Integer.parseInt(str2);//方法1: 调用Wrapper的静态的parseXxx(String)方法
boolean b1 = Boolean.parseBoolean(str3);
}
@Test//Primitive <---> Wrapper
public void test1(){
int i = 0;
System.out.println(i);
boolean a = false;
Integer i1 = new Integer(i);
System.out.println(i1.toString());
Float f = new Float(22.5F);
//Float f = new Float("22.5F");
System.out.println(f);
//java.lang.NumberFormatException
//i1 = new Integer("12abc");
//System.out.println(i1);
Boolean b = new Boolean("false");
System.out.println(b);//"false"
//Boolean: 当形参是"true" 返回true, 除此之外返回false
Boolean b1 = new Boolean("trueabc");
System.out.println(b1);// "false"
Order o = new Order();
System.out.println(o.c);//null
//Wrapper ---> Primitive: 调用包装类Xxx的XxxValue()方法
int i2 = i1.intValue();
System.out.println(i2);
//JDK 5.O后, autoboxing,unboxing
Integer i3 = 30;//autoboxing
Boolean jj = false;
int i4 = i3;//unboxing
}
class Order{
Boolean c;
}
static修饰属性, 方法, *代码块, *内部类
static修饰属性(类变量)
由类创建的所有的对象, 都共用这一个属性, 存在静态域中. 对此属性进行修改, 会导致其他对象对此属性的调用.
实例变量(非static修饰的变量,各个对象各自拥有一套副本)
类变量随着类的加载而加载,早于对象, 且只一份
实例变量(随着对象的创建而被加载)
静态的变量可以直接通过"类.类变量"来调用, 也可以通过"对象.类变量"来调用, 但是"类.实例变量"不行.
static修饰方法(类方法)
- static修饰的方法里不能有this|super
- constructor 看作和方法一样
静态的结构(static的field method 代码块 内部类)生命周期比非静态结构长: 加载早于非静态, 被回收晚于非静态
应用:
利用静态的变量达到累加的效果, 因为静态的内容独一份,被多个对象所共用, 比如记录创建对象的次数/ 每个对象某个属性有关联
public class TestAccount {
psvm{
Account a1 = new Account("abc", 1000);
Account a2 = new Account("CDF", 2000);
sout(a1);
sout(a2);
}
}
class Account{
private int id;//账号
private String password;
private double balance;
private static double minbalance = 1;
private static double rate = 0.05;//利率
private static int init = 1000;//初始金额
public Account(String password, double balance) {
this.id = init++;
this.password = password;
this.balance = balance;
}
...
}
代码块只能有static修饰
非静态代码块:
属性赋值的操作:
①默认的初始化
②显式的初始化||初始化块(此两结构按照顺序执行)
③构造器
——— 以上是对象的属性初始化的过程———
④通过方法对对象的相应的属性进行修改
public class TestOrder {
psvm {
Order o1 = new Order();
sout(o1);
Order o2 = new Order();
sout(o2);
}
}
class Order{
private int orderId = 1001;
private String orderName;
//静态代码块
{
orderId = 1002;
orderName = "AA";
sout("我是非静态代码块1")
}//我是非静态代码块1
//Order[orderId = 1002, orderId = AA]
static{
sout("静态代码块3")
}//静态代码块3
//我是非静态代码块1
//Order[orderId = 1002, orderId = AA]
...
}
修饰类, 属性, 方法
final class: 不能被继承, eg. String, StringBuffer, System
final method: 不能被重写, eg. Object.getClass()
final field: 此属性是常量. 用大写字符, eg. final int L
在哪赋值: ①不能默认赋值②可以显式赋值: 代码块, 构造器
全局常量: 被static, final修饰, eg. Math.PI
public static final double PI
diff: finally, finalize()
可以修饰类, 方法
不能被实例化, 但可以定义构造器
所有类都有构造器
有抽象方法的一定是抽象类, 抽象类不一定有抽象方法
若子类继承抽象类, 并重写了所有 的抽象方法, 则此类是"实体类", 即可以实例化;
若子类继承抽象类, 并未重写了所有 的抽象方法, 则此类仍为抽象类.
public class TestAbstract {
psvm {
//Person p1 = new Person();
//p1.eat;
Student s1 = new Student();
s1.eat;
}
abstract class Person {
String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
//abstract method
public abstract void eat();
public abstract void walk();
}
class Student extends Person {
public void eat() {
sout("student eat");
}
public void walk() {
sout("student walk");
}
}
}
总结: 抽象类作为多个子类的通用模版, 子类在抽象类的基础上拓展.
解决的问题:
public class TestInterface {
}
interface AA {
//常量
int I = 12//public static final int I = 12;所有常量都有这些修饰符,所以省略
//int i;不能有变量
//抽象方法
void method1();//public abstract void method1);所有方法都有这些修饰符,所以省略
}
abstract class BB implements AA {
}
class DD {
}
interface MM {
void method2();
}
//接口被类实现, 类能实现多个接口
class CC extends DD implements AA, MM {
public void method1() {
}
public void method2() {
}
}
//接口继承接口
interface JJ extends AA, MM {
void method1();
void method2();
}
在类的内部再定义类, 外面的类:外部类. 里面的类: 内部类
分类:
成员内部类:
局部内部类:
掌握:
- 如何创建成员内部类的对象
- 如何区分调用外部类, 内部类的变量(尤其是变量重名时)
- 局部内部类的使用
空指针 NullPointerException
@Test
public void test1() {
Person p = new Person();
p = null;
sout(p.toString());
}
数组下标越界 ArrayIndexOutOfBoundsException
@Test
public void test2() {
int[] i = new int[10];
sout(i[10]);
}
算术异常 ArithmeticException
@Test
public void test3() {
int i = 10;
sout(i / 0);
}
类型转换 ClassCastException
@Test
public void test4() {
Object obj = new Date();Date向上转型为Object
String str = (String)obj;将Object向下转型String, 但Date不支持
//String str = (String)new Date();编译异常
}
一旦出现异常, 下面的代码就不执行了
抓抛模型
try {
//可能出现异常的代码
} catch (Exception e1) {
//处理的方式1
} catch (Exception e2) {
//处理的方式2
}
finally {
//一定要执行的代码
}
try内声明的变量,类似于局部变量, 出了try{}, 就不能被调用
finally{ }可省略
catch() 对异常对象的处理:
可以有多个catch(), try{} 中抛出的异常类从上往下匹配catch()中异常类的类型, 满足一个并执行完处理方式后就跳出其后多条catch(). 异常处理之后的代码可以执行
catch()中多个异常类型是子父类, 子类必须放上面, 否则编译不通过
finally{ }中的代码一定被执行, 不管try{}, catch() {}中是否有仍未处理的异常/ 是否有return
try-catch可以嵌套
throws
在方法声明处, 显式抛出该异常对象的类型.
public staic void method() throws Exception{
...
}
2. “抛”: 当我们执行代码时,一旦出现异常,会在异常代码处生成一个对应的异常类型的对象,并将此对象抛出,且程序终止.(自动抛/手动抛)
此异常类的对象抛给方法的调用者
手动抛throw
+ 异常类的对象
throw new RuntimeException("wrong");
自定义异常类
仿造RuntimeException
子类重写父类方法, 抛出的异常类型 <= 被重写的方法抛的异常
public class TestCollection {
@Test
public void testCollection1() {
Collection coll = new Arraylist();
//1. size();返回集合中元素个数
sout(coll.size());
//2. add(Object obj);添加一个元素,*默认是object*
coll.add(123);
coll.add("aa");
coll.add(new Date());
//3. addAll(Collection coll):
Collection coll1 = Arrays.asList(1,2,3);
coll.addAll(coll1);
sout(coll.size());//6
//查看集合元素
sout(coll);//Arraylist重写了toString()
//4. isEmpty(); return boolean
//5. clear();
}
@Test
public void testCollection2() {
Collection coll = new Arraylist();
coll.add(123);
coll.add("aa");
coll.add(new Date());
coll.add("bb");
//6. contains(Object obj)
//判断依据: 根据元素所在类的equals()进行判断,
//如果存入集合中的元素是自定义类的对象.要求:自定义类要重写euqals()!
boolean b1 = coll.comtains(123)
//7. containsAll(Collection coll)
Collection coll1 = new Arraylist();
coll1.add(123);
coll1.add("AA");
boolean b3 = coll.containsAll(coll1);
sout("#" + b3);
}
}
public class TestIterator {
@Test
public void testIterator() {
Collection coll = new Arraylist();
coll.add(123);
coll.add("aa");
coll.add(new Date());
// 迭代器遍历集合
Iterator i = coll.iterator();
while(i.hasNext()) {
sout(i.next());
}
// foreach遍历
for(Object o: coll) {
sout(o);
}
}
}
List接口(有序, 可重复)
Set接口(无序, 不重复)
无序!=随机
元素的位置根据hash值存储
hashcode(), equals(), compareTo()要重写, 保证得到一致的结果
HashSet(主要 实现类)
LinkedHashSet
TreeSet
HashSet是HashMap的一种特殊情况, 底层实现有关联
保存具有单向一对一的数据
key, value可以是任何引用类型数据
key常用Set存, 所以不允许重复, 需重写hashCode(), equals()
value常用String存
方法
HashMap(主要 )
TreeMap
类似TreeSet
Hashtable
过时, 线程安全. 不允许null作为key, value
子类: Properties
key, value都为String. 常用于处理属性文件
Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
Sout(user);
提供静态方法操作Collection, Map的元素
排序: reverse(List), shuffle(List), sort(List), sort(List,Comparator)
查找, 替换: Object max(Collection), Object max(Collection,Comparator), intfrequency(Collection,Object), void copy(List dest,List src), boolean replaceAll()
同步: synchronizedXxx()
public interface List<E> {
void add(E x);
Iterator<E> iterator();
}
class person<T> {
// 定义属性
private T info;
// 定义方法
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
// 定义构造器
public Person(T info) {
this.info = info;
}
}
- static 方法不能声明泛型
- try-catch中不能定义泛型
泛型方法
[访问权限] <泛型> 返回类型 方法名**([泛型标识 参数名称])** 抛出的异常
public class DAO {
public <E> E get(int id, E e) {
...}
}
若B是A的一个子类型(类/接口), G是有泛型声明的类/接口, G不是G子类型
?
, 如 List>
, Map>
List>
是List
、List
等各种泛型List的父类
List>
中元素是安全的, 因为返回的总是ObjectList>
中元素是不允许的, 除了null, 因为null是所有类型的成员有限制的通配符
枚举类对象的属性不应允许被改动**,** 所以应该使用 private final 修饰
enum
必须在枚举类的第一行声明枚举类对象
switch-case: case子句直接使用枚举值
主要方法:
values()
返回对象数组. 用于遍历所有枚举值valueOf(String str)
把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。否则,会有运行异常。实现接口
若需要每个枚举值在调用实现的接口方法呈现出不同的行为方式, 则可以让每个枚举值分别来实现该方法
enum Season implements Info{
SPRING("1", "A") {
public void show() {
sout("a");
}
},
SUMMER("2", "B") {
public void show() {
sout("b");
}
},
FALL("3", "C"),
WINTER("4", "D");
}
interface Info {
void show();
}
内置
@Override
: 限定重写父类方法, 只能用于方法@Deprecated
: 用于表示某个程序元素(类, 方法等)已过时@SuppressWarnings
: 抑制编译器警告自定义
public @interface MyAnnotation {
String str() default "hello";
}
元注解: 修饰其他注解
Retention
Target
Documented
Inherited
package java.io
File: 文件和目录路径名的抽象表示形式
能新建、删除、重命名文件/目录, 但不能访问文件内容本身。如果需要访问文件内容本身,需使用输入/输出流
File对象可以作为参数传递给流的构造函数
方法
访问文件名
getName()
getPath()
getAbsoluteFile()
getAbsolutePath()
getParent()
renameTo(File newName)
文件检测
exists()
canWrite()
canRead()
isFile()
isDirectory()
获取文件信息
lastModified()
length()
文件操作
createNewFile()
delete()
目录操作
mkDir()
mkDirs()
list()
listFiles()
分类
打开文件IO不属于内存中资源, 无法被自动回收, 应显式关闭IO.
.close()
用try-catch处理保证流一定关闭
FileInputStream/Reader
1.建立一个流对象,将已存在的一个文件加载进流。 FileReader fr = new FileReader(“Test.txt”);
2.创建一个临时存放数据的数组。 char[] ch = new char[1024];
3.调用流对象的读取方法将流中的数据读入到数组中。 fr.read(ch);
int read(byte[] b)
int read(char [] c)
int read(byte[] b, int offset, int length)
int read(char[] b, int offset, int length)
FileOutputStream/Writer
1.创建流对象,建立数据存放文件 FileWriter fw = new FileWriter(“Test.txt”);
2.调用流对象的写入方法,将数据写入流 fw.write(“text”);
3.关闭流资源,并将流中的数据清空到文件中 fw.close();
void write(byte[] b/char[] cbuf)
void write(byte[] b/char[] buff, int offset, int length)
void write(String str)
void write(String str, int off, int len)
在使用缓冲流类时,会创建一个内部缓冲区数组
缓冲流要“套接”在相应的节点流之上,提高了读写的效率,增加了一些新方法
BufferedInputStream/Reader
BufferedReader br.readline()
一次读一行BufferedOutputStream/Writer
flush()
System.in和System.out分别代表系统标准的输入和输出设备. 默认输入设备是键盘,输出设备是显示器
System.in的类型是InputStream System.out的类型是PrintStream, 是OutputStream的子
类FilterOutputStream的子类
通过System类的setIn(),setOut()对默认设备进行改变
ObjectInputStream和OjbectOutputSteam
存储和读取对象的处理流
序列化(Serialize):用ObjectOutputStream类将一个Java对象 写入IO流中
反序列化(Deserialize):用ObjectInputStream类从IO流中恢复该Java对象
ObjectOutputStream和ObjectInputStream不能序列化static
和 transient
修饰的成员变量
类及属性都要实现Serializable接口才能序列化
实现Serializable接口的类都有一个表示序列化版本标识符的静态变量: private static final long serialVersionUID
应显示定义.
如果类没有显示定义这个静态变量,它的值是Java运行时自动生成。若类的源代码作了修改,serialVersionUID可能发生变化
用途: 类的不同版本间的兼容性
跳到文件的任意地方来读、写文件
RandomAccessFile对象包含一个记录指针,用以标示当前读, 写处的位置。RandomAccessFile 类对象可以自由移动记录指针:
long getFilePointer()
: 获取文件记录指针的当前位置
void seek(long pos)
: 将文件记录指针定位到 pos 位置
构造器
public RandomAccessFile(String name, String mode)
mode 指定 RandomAccessFile 的访问模式:
➢ r: 以只读方式打开
➢ rw:打开以便读取和写入
➢ **rwd:**打开以便读取和写入;同步文件内容的更新
➢ **rws:**打开以便读取和写入;同步文件内容和元数据的更新
创建线程第一种方法: 继承Thread类
void start(): 启动线程,并执行对象的run()方法
run(): 线程在被调度时执行的操作
String getName(): 返回线程的名称
void setName(String name):设置该线程名称
static currentThread(): 返回当前线程
static void yield(): 暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
join() :当某个程序执行流中调用其他线程的 join() 方法时, 调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止
static void sleep(long millis):(指定时间:毫秒) 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。
线程的优先级控制
MAX_PRIORITY(10); MIN _PRIORITY (1); NORM_PRIORITY (5);
方法:
创建线程第二种方法: 实现Runnable接口. 更好
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
. . .}
}
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
提出的问题:
多个线程操作共享数据可能出现一个线程未执行完毕时, 另外的线程参与进来而破坏数据。
解决办法***
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中, 其他线程不可以参与执行。
同步代码块
所有线程必须共用同一把锁; 包裹的代码块不多也不少, 只有共享数据的部分
// 可以用任意一个类的对象充当同步监视器(锁)
Object obj = new Object();
public void run() {
// Object obj = new Object(); 这样会导致每个线程自己有一把锁, 没有同步的作用
synchronized(obj) {
// 需要被同步的代码
}
}
同步方法
同步方法(非静态的)的锁为this。
同步方法(静态的)的锁为当前类本身。
public synchronized void show (String name){
...}
互斥锁 mutex
防止两条线程同时对同一公共资源进行读写的机制
锁
释放锁:
wait()
, 暂停当前线程, 并释放锁不会释放锁:
sleep()
, yield()
暂停当前线程死锁
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁.
减少同步资源的定义.
java.lang.Object
wait()
令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问notify()
:唤醒正在排队等待同步资源的线程中优先级最高者notifyAll()
:唤醒正在排队等待资源的所有线程这三个方法只有在synchronized方法或代码块中使用,否则会报 java.lang.IllegalMonitorStateException异常
常量池理解
字符串对象操作
字符串对象修改
public String substring(int startpoint)
public String substring(int start,int end)
pubic String replace(char oldChar,char newChar)
public String replaceAll(String old,String new)
public String trim()
public String concat(String str)
public String[] split(String regex)
包装类, 基本数据类型, 字节/字符数组 相互转换
字符串 与 基本数据类型, 包装类 转换
字符串 与 字节数组 转换
字符串 -> 字节数组: 字符串的getBytes()
字节数组 -> 字符串: 字符串的构造器
字符串 与 字符数组 转换
java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删改查. 线程安全.
添加 append()
删除 delete(int start, int end)
修改 setCharAt(int index, char ch)
插入 insert()
反转 reverse()
长度 length()
java.lang.StringBuilder和StringBuilder类似, 效率更高, 但线程不安全
java.lang.System类下的public static long currentTimeMillis(), 用于计算时间差
java.util.Date (及其子类 java.sql.Date)
java.text.SimpleDateFormat
不与语言环境有关的方式来格式化和解析日期的具体类.
格式化(日期->文本)、解析(文本->日期)
java.util.Calendar
抽象基类,主用用于完成日期字段之间相互操作的功能
获取Calendar实例的方法
get(), add(), Date getTime()/setTime(Date d)
java.lang.Math提供了一系列静态方法用于科学计算;其方法的参数和返回值类型一般为double型
支持任意精度
**Reflection(反射)**是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息且能直接操作.
若已知具体的类,通过类的class属性获取,该方法最安全可靠,性能最高
Class clazz = String.class;
已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class clazz = “hello, world”.getClass();
已知一个类的全类名,且该类在类路径下,可通过 Class类的静态方法forName() 获取,可能抛ClassNotFoundException
Class clazz = Class.forName(“java.lang.String”);
类的加载器(了解)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
getResourceAsStream(String str)
:获取类路径下的指定文件的输入流
创建类的对象
newInstance()
获取对应的运行时类的属性
Field[] getFields()
获取类中及其父类中声明为public的属性Field[] getDeclaredFields()
获取类本身声明的所有属性
int getModifiers()
以整数形式返回此Field的修饰符Class> getType()
得到属性类型String getName()
返回属性名获取对应的运行时类的方法
Method[] getMethods()
返回类或接口本身的public的方法Method[] getDeclaredMethods()
返回类及父类的全部方法
Class> getReturnType()
取得全部的返回值Class>[] getParameterTypes()
取得全部的参数int getModifiers()
取得修饰符Class>[] getExceptionTypes()
取得异常信息构造器
public Constructor[] getConstructors()
public Constructor[] getDeclaredConstructors()
public int getModifiers()
public String getName()
public Class>[] getParameterTypes()
注解
getAnnotation(Class
getDeclaredAnnotations()
泛型
Type getGenericSuperclass()
ParameterizedType
getActualTypeArguments()
包
Package getPackage()
属性
public Field getField(String name)
返回public的属性名为name的属性。
public Field getDeclaredField(String name)
返回属性名为name的属性。
public Object get(Object obj)
取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value)
设置指定对象obj上此Field的属性内
容
当类中属性设置为private,在使用set()和get()方法时,首先要使用Field类中的
setAccessible(true)
方法将需要操作的属性设置为可以被外部访问
方法
通过Class类的getMethod(String name,Class...parameterTypes)
方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
调用Class.newInstance()
若原方法声明为private,则需要在调用invoke()方法前, 显式调用方法对象setAccessible(true)
方法,将可访问 private的方法。
之后使用Object invoke(Object obj, Object[] args)
进行调用,并向方法中传递要设置的obj对象的参数信息。
代理模式: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象
动态代理步骤
Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
创建一个代理类对象invoke()
调用AOP (Aspect Orient Programming)
如何实现网络中主机互相通信
IP, 端口号
IP
域名-(DNS)->IP
java.net.InetAddress类
没有公共构造器, 提供2个静态方法获取实例:
getByName(String host)
getByAddress(byte[] addr)
端口号: 进程
16位整数 0-65535. 其中0-1023被预先定义占用.
网络通信协议
TCP(Transmission Control Protocol)
使用TCP协议前,须先采用“三次握手”方式建立连接
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,“四次挥手”
可靠但效率低
UDP(User Datagram Protocol)
将数据、源、目的封装成数据包,不需要建立连接
每个数据报的大小限制在64K内
因无需连接,故是不可靠的
发送数据结束时无需释放资源,速度快
Socket 套接字
当server使用阻塞IO(如InputStream.read()), 在数据没有到达前,read 会挂起,进程会卡住. 需要client在发送完数据后, 显式告诉server发送完毕(
void shutdownOutput()
)
UDP通信
DatagramSocket与DatagramPacket
UDP数据报通过数据报套接字DatagramSocket发送和接收,
DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号
建立发送端,接收端
建立数据包
调用Socket的发送、接收方法
关闭Socket
URL编程
java.net.URL类
InputStream openStream()
:能从网络上读取数据URLConnection openConnection()
生成URLConnection对象