Java期末复习总结篇

0x01 Java语言基础知识

Java程序的特点

  1. Java是面向对象的程序设计语言:可重用性、可靠性

将客观事物看作具有状态和行为的对象,通过抽象找出同一类对象的共同状态和行为,构成类。

  1. 安全性
  2. 平台无关性:编译后可在不同平台上运行
  3. 多线程
  4. 内存管理:Java对内存自动进行管理并进行垃圾回收
  5. 编译型语言(Java的开发环境)

先通过编译器(Javac)编译为 .class文件,再由解释器(Java)从 .class文件中读一行解释一行

Java的特征(面向对象语言特征)

  1. 抽象和封装:抽象的结果形成类。可以根据需要设置不同的访问控制属性
  2. 继承性:可以对已有类增加属性和功能,或进行部分修改来建立新的类。实现代码的重用
  3. 多态性:在面向对象的程序中,同一个消息被不同的对象接收后可以导致不同的行为

基本数据类型与表达式

种类

基本数据类型:数字型、字符型、布尔型
引用数据类型:类、接口、数组

标识符

第一个字符必须是大写字母、小写字母、_或$,后面的字符可以是字母,下划线,$或数字
数字不能作为标识符第一个字母
不能含有非法字符
关键字不能作为标识符

变量与常量

与C语言基本相同,在常量前加final关键字

//几种文字量类型
		System.out.println(100);
		System.out.println(3.14);
		System.out.println(true);
		System.out.println(false);
		System.out.println('a');
		System.out.println('中');
		System.out.println("abc");
//		System.out.println('ab'); 会编译报错,因为ab为字符串型要用双引号
		System.out.println("国");// 这不属于字符型,因为使用双引号括起来了,所以是字符串型

命名规范

  1. 包名:全小写,中间可以由点分隔开,独一无二
    如:java.io.* ; java.awt.event;
  2. 类名、接口名:首字母大写,通常由多个单词合成一个类名,要求每个单词的首字母也要大写
    如:class HelloWorld; interface Collection
  3. 方法名:由多个单词合成,第一个单词为动词,首字母小写,后面的每个单词首字母大写
    如:setName;getScore
  4. 变量名:全小写,要有具体含义
    如:length
  5. 常量名:一般为全大写,如果由多个单词合成,可以用下划线隔开
    如:int YEAR;int WEEK_OF_MONTH

类型转换

扩展转换
byte, char, short, int, long, float, double:整数向float或double转换时会损失精度
窄化转化
double, float, long, int, short, byte,char:可能会丢失信息
转换方法(Java是强类型语言,赋值操作时对类型检查):赋值转化(将表达式类型转换为指定变量的类型,只能扩展转换)、方法调用转换、强制转换、字符串转化(任何类型都可以转换为字符串类型)

表达式

表达式是由一系列变量、运算符、方法调用构成

标准输入输出

标准输入流:System.in
标准输出流:System.out

数组

数组由同一类型的一连串对象或基本数据组成,并封装在同一个标识符。
数组是对象,数组名是一个引用。
在数组中可以调用Object类的所有方法

数组声明:Type[] arrayName;Type arrayName[]

int[] intArray;
String[] stringArray;
int intArray[]
String stringArray[]

数组的创建:arrayName = new Type[componets number];

int [] ai; 
ai = new int[10];//元素个数可以是常量也可以是变量

int ai[] = new int[10];

数组初始化:如果在声明时给出了数组的初始值,则程序将利用初始值创建数组并进行初始化;如果没有指定初始值则默认为0,false,null

数组的引用:arrayName[index] index类型为int short byte char
元素的个数:arrayName.length;下标最大值 length-1(从0开始计数),当下标超过最大值会产生ArrayIndexOutOfBoundsException

多维数组:可以为整个数组分配对象、也可以为每一行单独分配内存(当每行的元素个数不同时),数组中每行的个数可以不同

0x02 类与对象

将属性及行为相同或相似的对象归为一类,可以看做是对象的抽象

  1. 抽象:忽略问题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。
  2. 封装:利用抽象数据类型将数据和基于数据的操作封装在一起,对象的内部细节对用户是透明的。清楚的边界、有接口与外界交互、受保护的内部实现
  3. 继承:新的类可以获得已有类(称为超类、基类或父类)的属性和行为,称新类为已有类的派生类(也称为子类) 在继承过程中派生类继承了基类的特性,包括方法和实例变量,派生类也可修改继承的方法或增加新的方法,使之更适合特殊的需要。单继承
  4. 多态:一个程序中同名的不同方法共存,子类对父类方法的覆盖

类VS对象:对象是类的具体实例。类是构造对象的模板,对象在Stack中存储,类在Heap中创建

具体应用代码

  1. 类的声明
[public][abstract | final] class classname [extends father_class] [implements interfaces_name]{
    
    
	//变量成员声明及初始化
	//方法声明及方法体
}

注:每个编译单元(文件)只能有一个public类。即每个编译单元只能有一个公开的接口。public类的名字必须和这个编译单元的文件名完全相同。

  1. 对象的创建
Clock aclock; //对象的声明,并没有对象生成
aclock = new Clock();//在内存中为此对象分配内存空间
//aclock变量存储对象的引用,相当于对象的存储地址
  1. 数据成员:
    实例变量:没有static修饰的变量
    类变量(静态变量):声明时要加static修饰符,在初始化的同时被赋值,不管类的对象有多少,类变量只存在一份,在整个类中只有一个值
[public| protected| private]//访问控制符
[static]//静态成员变量
[final]//常量的值不能被改变
[transient]//变量是临时状态
[volatile] //变量是一个共享变量
数据类型 变量名1[=value1];

//类变量实例
public class Point 
{
    
    
   private int x;
   private int y;
   public static int pointCount=0;
   
   public Point(int x, int y){
    
    
     this.x = x; 
     this.y = y; 
     pointCount++;
   }
	public static void main(String[] args)
    {
    
    
		  Point p = new Point(1,1);
        System.out.println(p.pointCount);// 1
		  Point q = new Point(2,2);
		  System.out.println(q.pointCount);// 2
		  System.out.println(q.pointCount == Point.pointCount);// true
		  System.out.println(Point.pointCount);// 2
	}
}
  1. 方法成员:定义类的行为
[public | protected | private]
[static][final][abstract][native][synchronized] 返回类型 function_name(argv[0] value0,[argv[1] value1...]) [throw exception1,exception2...]{
    
    
	方法体
}

实例方法:表示特定对象的行为,声明时前面不加static修饰符,需要在一个类实例上调用

public class Circle {
    
     
	 static double PI = 3.14159265; 
	 int radius;     
	 public double circumference() {
    
     
	 	return 2 * PI * radius; 
	 } 
}	

类方法:静态方法,表示类中对象共有的行为,需要加static修饰符,可以在不建立对象的情况下利用类名直接调用
不能使用this/super,使用时可用ClassName.var/ClassName.method()调用
不能被重写(但可以被隐藏(即除方法体其他均相同))

在静态方法中只能直接调用静态变量,静态方法或对象的属性和方法,不能直接使用非静态方法和非静态变量

public class Converter {
    
     
  public static int centigradeToFahrenheit(int cent)
  {
    
     
  	return (cent * 9 / 5 + 32);   
  }  
 }
//方法调用
Converter.centigradeToFahrenheit(40)
  1. 包的概念
    将相关的源代码文件组织在一起
    用import导入外部的类、同一个包中的类不需要import
    关键字顺序:package import class
  2. 类的访问控制
    在这里插入图片描述
    要修改private变量只能通过添加set和get方法得到
public class Circle {
    
     
        static double PI = 3.14159265; 
        private int radius;     
  		public double circumference() {
    
     
            return 2 * PI * radius; 
        } 
        public int getRadius(){
    
    
  			 return radius;
		} 
		public void setRadius(int r){
    
    
  			 radius = r;
		}
  }
  public class CircumferenceTester {
    
     
      public static void main(String args[]) {
    
     
           Circle c1 = new Circle(); 
//           c1.radius = 50;  编译器会报错,无法修改
		   c1.setRadius(50);
           Circle c2 = new Circle(); 
//           c2.radius = 10;  编译器会报错,私有变量无法从外部类直接修改
		   c2.setRadius(10);    //正确方法   
	       double circum1 = c1.circumference(); 
           double circum2 = c2.circumference(); 
           System.out.println("Circle 1 has circumference " + circum1); 
           System.out.println("Circle 2 has circumference " + circum2); 
     } 
 }
  1. final修饰符
    可以修饰类、方法、变量
    修饰类时,此类不可被继承
    修饰方法时,方法不能被重写
    修饰变量时,变量变为常量,必须有初始化,不能被改变
  2. 构造方法
    如果在类的声明中没有声明构造方法,Java编译器会默认一个构造方法,没有参数,方法体为空,对象的属性值为0或null(无初始化时)
    但当声明构造方法时,就不在有默认的构造方法
  3. 方法重载
    在Java中,同一个类中的多个方法可以有相同的方法名称,但是有不同的参数列表,这就称为方法重载
    参数列表不同包括:个数不同、顺序不同、类型不同。
    仅仅参数变量名称不同是不可以的。跟成员方法一样,构造方法也可以重载。声明为final的方法不能被重载。
    声明为static的方法不能被重载,但是能够被再次声明
    方法的重载的规则:
    方法名称必须相同。参数列表必须不同。方法的返回类型可以相同也可以不相同。仅仅返回类型不同不足以称为方法的重载。
  4. this关键字
    1. 可以使用this关键字在一个构造方法中调用另外的构造方法
    2. 对this的调用必须是构造函数中的第一个语句
    3. 通常用参数个数比较少的构造方法调用参数个数最多的构造方法
    4. 通常也用在区分本类中的参数与引用的参数(当变量名相同时)
public BankAccount() {
    
     
        this("", 999999, 0.0f); 
} 
public BankAccount(String initName, int initAccountNumber) {
    
     
	  this(initName, initAccountNumber, 0.0f);    
}
public BankAccount(String initName, int initAccountNumber,
 float initBalance) {
    
     
         ownerName = initName; 
         accountNumber = initAccountNumber; 
         balance = initBalance; 
 }
 public void saveMoney(double balance){
    
    
	this.balance = balance;
}

UML

  1. 类图
    在这里插入图片描述
  2. 类的关系表示
    在这里插入图片描述
    聚集:表示部分与整体关系的关联
    一个人可以参加零个或多个课题组,每个课题组至少包含一个人。课题组与人之间是聚集的关系,如图
    组成:部分类完全隶属于整体类,部分与整体共存
    在这里插入图片描述
    泛化:也就是常说的继承
    在这里插入图片描述

0x03 继承、抽象、组合

继承

语法:

class childClass extends parentClass{
    
    
	类体
}
public class Person {
    
    
  public String name;
  public String getName() {
    
     
   return name; 
  }
} 
public class Employee extends Person {
    
     
    public int employeeNumber; 
    public int getEmployeeNumber() {
    
     
       return employeeNumber; 
    } 
} 
public class Manager extends Employee {
    
     
    public String responsibilities; 
    public String getResponsibilities() {
    
     
      return responsibilities;
    } 
}

子类不能直接访问从父类中继承的私有属性及方法,但可使用公有(及保护)方法进行访问

public class B {
    
     
   public int a = 10; 
   private int b = 20; 
   protected int c = 30; 
   public int getB()  {
    
     return b; } 
} 
public class A extends B {
    
     
   public int d; 
   public void tryVariables() {
    
     
      System.out.println(a);             //允许 
      System.out.println(b);             //不允许
      System.out.println(getB());        //允许 
      System.out.println(c);             //允许 
    } 
}
  1. 属性的隐藏:子类中声明了与父类相同的成员变量名,则从父类继承的变量被隐藏。可以利用super.属性(方法)访问被隐藏的父类属性和方法。是针对于成员变量和静态方法而言的
  2. 方法的覆盖:覆盖方法的返回类型,方法名称,参数的个数及类型必须和被覆盖的方法一摸一样,是针对于实例方法而言的
    注:有抽象类必有覆盖方法,final和static方法不能被覆盖,若父子有同为static方法则为隐藏

终结类与终结方法

被final修饰符修饰的类和方法
终结类不能被继承
终结方法不能被当前类的子类重写

抽象类(abstract)

不能被实例化,必须有子类覆盖其声明的方法

包的应用

Java基础类库:java.lang、java.util、java.io

泛型

本质是参数化类型,所有类型转换都是自动和隐式的
泛型类:在类名后面加上<Type>
泛型方法:在方法名前加上<Type>

class GeneralType <Type> {
    
    
    Type object;
    public GeneralType(Type object) {
    
    
        this.object = object;
    }
    public Type getObj() {
    
    
        return object;
    }
}
public class Test {
    
    
    public static void main(String args[]){
    
    
        GeneralType<Integer> i = new GeneralType<Integer> (2);
        GeneralType<Double> d = new GeneralType<Double> (0.33);
        System.out.println("i.object=" + (Integer)i.getObj());
//      System.out.println("i.object=" + (Integer)d.getObj());  不能通过编译
    }
}
  • 通配符泛型
class GeneralType <Type> {
    
    
    Type object;
    public GeneralType(Type object) {
    
    
        this.object = object;
    }
    public Type getObj() {
    
    
        return object;
    }
}
class ShowType {
    
    
    public void showType(GeneralType<?> o) {
    
    //"?"表示通配符,可以传入任意类型的数据
        System.out.println(o.getObj().getClass().getName());
    }
}
public class Test {
    
    
    public static void main(String args[]){
    
    
        ShowType st = new ShowType();
        GeneralType<Integer> i = new GeneralType<Integer> (2);
        GeneralType<String> s = new GeneralType<String> ("hello");
        st.showType(i);
        st.showType(s);
    }
} 
//程序的运行结果如下:
//java.lang.Integer
//java.lang.String
  • 有限制的泛型
    在参数“Type”后面使用“extends”关键字并加上类名或接口名,表明参数所代表的类型必须是改类的关键字或者实现了该接口
class GeneralType <Type extends Number> {
    
    
    Type object;
    public GeneralType(Type object) {
    
    
        this.object = object;
    }
    public Type getObj() {
    
    
        return object;
    }
}
public class Test {
    
    
    public static void main(String args[]){
    
    
        GeneralType<Integer> i = new GeneralType<Integer> (2);
        //GeneralType<String> s = new GeneralType<String> ("hello");//非法,
                                       //T只能是Number或Number的子类
    }
}

0x04 接口与多态

接口

是一个纯抽象类,允许创建者规定方法的基本形式:方法名、参数列表以及返回类型,但不规定方法主体,也可以包含基本数据类型的数据成员,但都默认为static和final
为了实现多继承
注:接口数据成员为static/final,方法成员为abstract
接口作用:允许我们在看起来不相干的对象之间定义共同行为
在这里插入图片描述

//接口定义
interface 接口名称 [extends 父接口名]{
    
    
	/*方法的原型声明或静态常量,数据成员一定要赋值,可以忽略public和abstract关键字*/
}
public interface Insurable {
    
    
	public int getNumber(); 
	public int getCoverageAmount(); 
	public double calculatePremium(); 
	public Date getExpiryDate(); 
}

//接口实现
public class 类名称 implements 接口名称{
    
     
/* Bodies for the interface methods */ /* Own data and methods. */ 
}
//必须实现接口中所有方法,来自接口的方法必须声明成public

塑性(类型转换)

  1. 塑造对象包括:基本数据类型、引用变量(父类、接口,本身的类)
  2. 方法:
  • 隐式的类型转换
    相容类型之间存储容量低的自动向存储容量高的类型转换
//被塑性成更一般的类
Employee emp;
emp = new Manager();//将Manager类型的对象直接赋给Employee类的引用变量,将Manager对象塑性为Employee类

//被塑性为对象所属类实现的接口类型
Car jetta = new Car();
Insurable item = jetta;
  • 显式的类型转换
//基本数据类型
(int)871.34354;  //871
(char)65;//'A'
(long)453; // 453L

//引用变量:还原为本来的类型
Employee emp;
Manager man;
emp = new Manager();//将Manager向上塑型为Employee,此时emp中如果有被重写的方法,则调用Manager类中的方法,但此时不能调用Manager类中的特有方法
man = (Manager)emp;//将Manager还原回去,此时可以调用Manager类中的特有方法
//在向上和向下的塑型过程中一直只有一个Manager被转换,不能转换为Employee的其他子类,只能向下塑型回Manager类
  1. 应用场合

    1. 赋值转化:赋值号右边的表达式或对象转换为左边的类型
    2. 方法调用转化:实参的类型转换为形参的类型
    3. 算数表达式转换
    4. 字符串转化
  2. 方法的查找

  • 实例方法:从对象创建时的类开始,沿类层次向上查找
  • 类方法:总是在引用变量声明时所属的类中进行查找

多态

  1. 指不同类型的对象可以响应相同的消息
  2. 目的:所有的对象都可被塑性为相同的类型,响应相同的消息、代码简单易于理解、很好的扩展性
  3. 绑定:将一个方法调用同一个方法主体连接到一起
    动态绑定:基于对象的类别,在程序运行时执行绑定
  4. 原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。通过继承和接口实现多态
public class BindingTester{
    
     
	public static void main(String[] args) {
    
     
			Shape[] s = new Shape[9]; //Shape为Circle、Square、Triangle的基类
			int n;
			for(int i = 0; i < s.length; i++) {
    
     
				n = (int)(Math.random() * 3);
				switch(n) {
    
     
					case 0: 
						s[i] = new Circle(); 
						break;
					case 1: 
						s[i] = new Square(); 
						break;
					case 2: 
						s[i] = new Triangle();
					} 
				} 
			for(int i = 0; i < s.length; i++) s[i].draw(); 
	}
}//编译时无法知道s数组元素的具体类型,运行时才能确定类型,所以是动态绑定

在这里插入图片描述

0x05 对象群体的组织

对象数组

数组元素都是类的对象、所有元素具有相同的类型、每个元素都是一个对象的引用

  1. 对象数组的初始化
//在声明和定义数组的同时对数组元素进行初始化
BankAccount[] accounts = {
    
     
                new BankAccount(“Zhang", 100.00), 
                new BankAccount(“Li", 2380.00),
                new BankAccount(“Wang", 500.00),
                new BankAccount(“Liu", 175.56),
                new BankAccount(“Ma", 924.02)};
//先定义再初始化
//首先给数组分配空间
type arrayName[] = new type[arraySize];
//然后给每一个数组元素分配空间
arrayName[0] = new type(paramList);
...
arrayName[arraySize-1] = new type(paramList);

集合

可以动态改变其大小,在序列中存储不同类型的数据
在这里插入图片描述

Collection集合

List

元素有顺序,每个元素都有对应的index值,元素可以重复
非同步的

  • ArrayList
    有序、元素可以为null、效率高、占用空间小
  • LinkedList
    双向链表,只能从头开始遍历
  • List与Array的区别
相同 不同
都可以表示一组同类型的对象 数组可以存任何类型元素,List不可以存基本数据类型
都使用下标进行索引 数组容量固定,List容量可变
数组效率高,List效率低一些
  • Vector
    与ArrayList并列
    同步的
Stack

push入栈
pop栈顶元素出栈,并返回
peek获取栈顶元素

Set

禁止重复元素,HashSet,其中哈希函数为hashCode

常用方法

声明了一组操作成批对象的抽象方法:查询方法、修改方法
查询方法
int size() – 返回集合对象中包含的元素个数
boolean isEmpty() – 判断集合对象中是否还包含元素,如果没有任何元素,则返回true
boolean contains(Object obj) – 判断对象是否在集合中
boolean containsAll(Collection c) – 判断方法的接收者对象是否包含集合中的所有元素
修改方法包括
boolean add(Object obj) – 向集合中增加对象
boolean addAll(Collection<?> c) – 将参数集合中的所有元素增加到接收者集合中
boolean remove(Object obj) –从集合中删除对象
boolean removeAll(Collection c) -将参数集合中的所有元素从接收者集合中删除
boolean retainAll(Collection c) – 在接收者集合中保留参数集合中的所有元素,其它元素都删除
void clear() – 删除集合中的所有元素

Map

不是Collection接口的继承
存在键值对,不能有重复关键字,每个关键字映射一个值
HashMap速度很快,但没有顺序

Java集合框架

在这里插入图片描述

  1. Collection接口
  2. Set、SortedSet接口:禁止重复的元素
  3. List接口:可包含重复元素,有顺序
  4. Map、SortedMap接口:不是Collection接口的继承,描述了从不重复的键到值的映射

集合遍历(Iterator)

hasNext():判断是否还有元素
next():取得下一个元素
remove():去除一个元素,是从集合中去除最后调用next()返回的元素,而不是从Iterator类中去除

import java.util.Vector; 
import java.util.Iterator; 
public class IteratorTester {
    
     
  public static void main(String args[]) {
    
     
    String[]  num = {
    
    "one", "two", "three", "four", "five", 
                              "six", "seven", "eight", "nine", "ten"}; 
    Vector<String>   aVector = new Vector<String> (java.util.Arrays.asList(num)); 
    System.out.println("Before Vector: " + aVector); 
    Iterator<String> nums = aVector.iterator(); 
    while(nums.hasNext()) {
    
     
      String aString = (String)nums.next(); 
      System.out.println(aString); 
      if (aString.length() > 4)    nums.remove();
    } 
    System.out.println("After Vector: " + aVector);
  }
}

0x06 IO流(java.io包)

在Java中将信息的输入与输出过程抽象为I/O流

流的分类

  • 从流的处理来分
    - 节点流:从数据源读入或往目的地写出数据
    - 处理流:对数据执行某种处理(不直接与数据源或目标相连,而是基于另一个流来构造)

  • 从流的内容划分

    • 面向字符的流:专门用于字符数据(文本文件)
      在这里插入图片描述
    • 面向字节的流:用于一般目的
      在这里插入图片描述

基本输入输出

//输入单个字符
import java.util.Scanner;
public class Demo59 {
    
    
	public static void main(String[] args) {
    
    
		//创建Scanner对象,接受从控制台输入
		Scanner input=new Scanner(System.in);//默认为键盘;System.in  程序启动时自动创建的流对象,是原始的字节流
//		setIn(InputStream);设置标准输入流
//		setOut(PrintStream); 设置标准输出流
		//接受String类型
		String str=input.next();
		//输出结果
		System.out.println(str);//默认为屏幕输出
	}
	
 //输入一串字符
import java.util.Scanner;
public class Demo59 {
    
    
	public static void main(String[] args) {
    
    	
		Scanner input=new Scanner(System.in);
		//输入数组的长度
		int len=input.nextInt();//根据返回类型不同,进行更改,nextByte(),nextDouble(),nextFloat,nextInt(),nextLine(),nextLong(),nextShort()
		//创建一个数组
		int[] array=new int[len];
		//遍历数组,并给其赋值
		for(int i=0;i<len;i++){
    
    
			array[i]=input.nextInt();
		}
		//打印数组
		for(int i:array){
    
    
			System.out.print(i+" ");
		}
	}
}
//持续输入并随之回车输出
import java.io.*;
public class Echo {
    
    
    public static void main(String[] args)  throws IOException {
    
    
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        //BufferedReader 对InputStreamReader处理后的信息进行缓冲,InputStreamReader属于处理流
        String s;
        while((s = in.readLine()).length() != 0)
           System.out.println(s);
      }
  } 
 

文件读写

写入文本文件(Reader、Writer)

常用类:FileWriter(节点流)、BufferedWriter、OutputStreamWriter

FileWriter类

//写入文件中
import java.io.*;   
class FileWriterTester {
    
    
  public static void main ( String[] args ) throws IOException {
    
      
     //main方法中声明抛出IO异常
     String fileName = "C:\\Hello.txt"; 
     //每次运行都将删除原有的文件,创建同名文件,重新写入
     FileWriter writer = new FileWriter( fileName );   		//一共有五种构造方法
     //FileWriter writer = new FileWriter( fileName ,true ); 
     //运行此句程序,会发现在原文件内容后面又追加了重复的内容,这就是将构造方法的第二个参数设为true的效果
     writer.write( "Hello!\n"); 
     writer.write( "This is my first text file,\n"  );  
     writer.write( "You can see how this is done.\n" ); 
     writer.write("输入一行中文也可以\n");
     writer.close(); 
  }
}

BufferedWriter类

当需要写入的内容很多时,利用更高效的缓冲器流类BufferedWriter

import java.io.*; 
class BufferedWriterTester {
    
    
	public static void main ( String[] args ) throws IOException	{
    
    
		String fileName = "C:/newHello.txt" ;
		BufferedWriter out = new BufferedWriter( new  FileWriter( fileName ) );
        out.write( "Hello!"  );
    	out.newLine() ; //换行
 		out.write( "This is another text file using BufferedWriter,"  );   
        out.newLine(); ;
        out.write( "So I can use a common way to start a newline" ); 
        out.close();
    }
}

读出文本文件

常用类:FileReader(节点流)、BufferedReader、InputStreamReader

FileReader类

继承自Reader抽象类的子类InputStreamReader,从文本文件中读取字符

BufferedReader类

读文本文件的缓冲器类,继承自Reader

//文件读入
import java.io.*;
class BufferedReaderTester {
    
    
    public static void main ( String[] args ) {
    
    
        String fileName = "C:/Hello.txt" , line;
        try {
    
    
             BufferedReader in = new BufferedReader(new FileReader( fileName  ) );//若文件不存在会抛出IOException
             line = in.readLine();   //读取一行内容
             while ( line != null ) {
    
     
       			System.out.println( line );
      			line = in.readLine();
     	      }
              in.close(); //一定要记得关闭文件
              //int c;
			  //while((c=in.read())!= -1)  System.out.print((char)c);
			  //Reader类的read()方法也可用来判别文件结束。该方法返回的一个表示某个字符的int型整数,如果读到文件末尾,返回 -1
        }
       catch ( IOException iox ) {
    
     
            System.out.println("Problem reading " + fileName );  
        }
    }
}

写二进制文件(OutputStream、InputStream)

常用类:FileOutputStream、BufferedOutputStream、DataOutputStream

import java.io.*; 
class FileOutputstreamTester {
    
    
  public static void main ( String[] args ) {
    
     
    String fileName = "c:/data1.dat" ;
     int value0  = 255, value1  = 0, value2 = -1;
     try {
    
    
        DataOutputStream out = new DataOutputStream(new FileOutputStream( fileName  ) );
        out.writeInt( value0 );
        out.writeInt( value1 );
        out.writeInt( value2 );
        out.close();
      }
      catch ( IOException iox ){
    
    
     	 System.out.println("Problem writing " + fileName );   }
      }
 }
 //写完后查看二进制信息,发现内容为00 00 00 FF 00 00 00 00 FF FF FF FF

BufferedOutputStream类

类似于BufferedWriter,对于大量数据的写入可以提高效率

//向文件中写入各种数据类型的数,并统计写入的字节数
import java.io.*; 
class BufferedOutputStreamTester {
    
    
  public static void main ( String[] args ) throws IOException {
    
    
    	String fileName = "mixedTypes.dat" ;
    	DataOutputStream dataOut = new DataOutputStream(
                             new BufferedOutputStream(
                               new FileOutputStream( fileName  ) ) );
    	dataOut.writeInt( 0 );
    	System.out.println( dataOut.size()  + " bytes have been written.");//4
    	dataOut.writeDouble( 31.2 );
    	System.out.println( dataOut.size()  + " bytes have been written.");//12
    	dataOut.writeBytes("JAVA");
    	System.out.println( dataOut.size()  + " bytes have been written.");//16
    	dataOut.close();
  }
}

读二进制文件

常用类:FileInputStream、DataInputStream、BufferedInputStream

import java.io.*;
class DataInputStreamTester {
    
    
  public static void main ( String[] args ) {
    
    
    	String fileName = "c:/data1.dat" ;   long sum = 0;
    	try {
    
    
    	    DataInputStream instr = new DataInputStream(
           new BufferedInputStream(new FileInputStream(fileName)));
         try {
    
    
            while ( true )
            sum += instr.readInt();
         }
         catch ( EOFException  eof ) {
    
    //遇到文件结尾会抛出此异常
           System.out.println( "The sum is: " + sum );
           instr.close();
         }
    }
    catch ( IOException iox ) {
    
    
    	    System.out.println("IO Problems with " + fileName ); }
    }
  }
}

//文本文件的存储方式也是二进制代码,也可以用InputStream类的方法读取
import java.io.*;
public class InputStreamTester {
    
    
	public static void main(String[] args) throws IOException {
    
    
	    FileInputStream s=new FileInputStream("c:/Hello.txt");
        int c;
        while ((c = s.read()) != -1) //读取1字节,结束返回-1
            System.out.write(c);     
        s.close();
    }
}

0x07 异常处理

异常处理的分类

总的分类

  1. 编译错误(Syntax errors):是编译器能够检测到的错误,一般是语法错误
  2. 运行错误(Runtime errors):运行过程中出现无法执行的操作(如被零除,数组下标越界等)
  3. 逻辑错误(Logic errors):机器无法检测,需要人对运行结果进行分析
    在这里插入图片描述

在这里插入图片描述

错误

在Error类下的错误都是用户程序无法解决的

异常

  1. 非检查型异常(Error和RuntimeException类的派生类):不需要进行声明,主要是程序错误
  2. 检查型异常:通常是程序的逻辑错误,必须在方法签名中声明所抛出的异常

异常的处理(检查型异常)

  1. 声明抛出异常(throws):不在当前方法内处理,而是把异常抛出到调用方法中
    使用情况:方法本身不知道如何处理这样的异常,或者说让调用者处理更好,调用者需要为可能发生的异常负责
public void openThisFile(String filename) throws FileNotFoundException{
    
    
}
//也可以同时抛出多个异常

public void openThisFile(String filename) throws FileNotFoundException,ClassNotFoundException{
    
    
}

//可以通过手动显式抛出一个异常(throw)
public void setRadius(double newRadius) throws IllegalArgumentException {
    
    
	if (newRadius >= 0)
		radius =  newRadius;
	else
		throw new IllegalArgumentException("Radius cannot be negative");
}
  1. 异常捕获:使用try{}catch(){}finally{},捕获到所发生的的异常,并进行相应的处理
//可以同时catch多个异常
try{
    
    
	statements;
}
catch(Exception1 exVar1){
    
    
	handler for exception1;//可用throw语句生产异常对象
	// throw new Exception(); 重复抛出异常
}
catch(Exception2 exVar2){
    
    
	handler for exception2;
}

//finally用法
//some codes
try {
    
    
  statements;
}
catch(TheException ex) {
    
    
	 handling ex;
}
finally {
    
     
	finalStatements;
}
Next Statements;
  • 在调用的方法中处理-> 抛出(当此方法是被调用的时候,发送的异常选择抛出,返回到上一层中去处理)
  • 在方法内部处理 -> 直接处理(如果是在此方法内部出现异常,则直接处理)

创建异常类

要extends Exception
同时在构造函数里面要super("");

Finally使用注意

  1. 当Exception在方法内解决后,会执行finally中的语句,然后继续执行Next Statements的语句;当catch中的解决办法是再次抛出异常时,会先执行finally中的语句,然后再抛出异常**(必须知道)**
  2. 但是当try前面的语句出现异常时,就不会再执行finally中的语句
  3. 在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行
  4. finally中的return会抑制(消灭)前面try或者catch块中的异常
  5. finally中的return 会覆盖 try 或者catch中的返回值
  6. 最好使用finally块来释放资源

0x08 线程

线程的概念

一个程序中多段代码同时并发执行

Thread类

实现了Runnable接口,位于java.lang包中

public class FactorialThreadTester{
    
    
	public static void main( String [] args) {
    
    
		System.out.println("main thread starts");
		FactorialThreadthread=new FactorialThread(10);
		thread.start(); //将自动进入run()方法System.out.println("main thread ends " );
		 }
}
class FactorialThread extends Thread{
    
    
	private int num;
	public FactorialThread( int num ) {
    
     
		this.num=num; 
	}
	public void run() {
    
     
		int i=num; 
		ntresult=1;
		System.out.println("new thread started" ); 
		while(i>0) {
    
     
			result=result*i; 
			i=i-1; 
		} 
		System.out.println("The factorial of "+num+" is "+result);
		System.out.println("new thread ends"); 
	} 
} 
//运行结果
//main thread starts   说明main函数启动后没有等待run()返回完成,就继续运行
//main thread ends
//new thread started
//The factorial of 10 is 3628800
//new thread ends	  

在启动多个线程的时候,程序启动线程的顺序是随机的

Runnable接口

  1. 只有一个run()方法
  2. 更便于多个线程共享资源(使用同一个数据)
//共用一个数据
public class TestThread implements Runnable{
    
    
	private int sleepTime; 
	public TestThread() {
    
    
		sleepTime= (int)(Math.random()*6000);
	}
	public void run() {
    
    
		try {
    
    
			System.out.println(Thread.currentThread().getName()+" going to sleep for "+sleepTime);
			Thread.sleep(sleepTime);
		}catch(InterruptedException exception) {
    
    };
		System.out.println(Thread.currentThread().getName()+" finished");
	}
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		TestThread thread1 = new TestThread();
		System.out.println("Starting threads");
		//使用Runnable接口的类要用Thread(Runnable target[,name]),方法创建对象
		new Thread(thread1,"Thread1").start();
		new Thread(thread1,"Thread2").start();
		new Thread(thread1,"Thread3").start();
		System.out.println("Threads strat,main ends\n");
	}
}
// 运行结果
//Starting threads
//Threads strat,main ends

//Thread1 going to sleep for 4506
//Thread2 going to sleep for 4506
//Thread3 going to sleep for 4506
//Thread3 finished
//Thread1 finished
//Thread2 finished

创建多线程的方法

  • 继承Thread类,重写Thread类中的run方法,并创建子类的对象,调用strat()方法启动新线程
  • 实现Runnable接口,利用Thread(target,name)创建,其中target为实现了Runnable接口的对象

多线程的同步控制

线程同步:
- 互斥:许多线程在同一个共享数据上操作而互不干扰,同一时刻只能有一个线程访问该共享数据,有些方法或程序段在同一时刻只能被一个线程执行,称之为监视区

Synchronized关键字

实现互斥,用于指点需要同步的代码段或方法
功能:判断这个对象可以不可以被使用(锁旗标在不在),如果可以(锁旗标在)就执行后面的代码段(拿走锁旗标);如果不能被使用(锁旗标不在,此数据被其他线程使用),就进入等待状态,直到可以使用此对象。用完后释放锁旗标

//将需要互斥的语句段放入synchronized(object){}语句中,且两处的object是相同的
class Producer extends Thread {
    
    
	Tickets t=null;
	public Producer(Tickets t) {
    
     
		this.t=t;
	}
	public void run() {
    
    
		while((t.number)<t.size) {
    
    
			synchronized(t){
    
     // 申请对象t的锁旗标
				System.out.println("Producer puts ticket" +(++t.number));
				t.available=true;
			} // 释放对象t的锁旗标
		}
		System.out.println("Producer ends!");
	}
}
class Consumer extends Thread {
    
    
	Tickets t=null;
	int i=0;
	public Consumer(Tickets t) {
    
     
		this.t=t; 
	}
	public void run() {
    
    
		while(i<t.size) {
    
    
			synchronized(t) {
    
     //申请对象t的锁旗标
				if(t.available==true && i<=t.number)
					System.out.println("Consumer buys ticket "+(++i));
				if(i==t.number) {
    
    
					try{
    
     
						Thread.sleep(1); 
					} catch(Exception e){
    
    }
					t.available=false;
					}
				}//释放对象t的锁旗标
			}
			System.out.println("Consumer ends");
		}
	} 

除了对指定的代码段进行同步控制,还可以定义整个方法在同步控制下进行

class Tickets {
    
    
	int size; //票总数
	int number=0; //存票序号
	int i=0; //售票序号
	boolean available=false; //是否有待售的票
	public Tickets(int size) {
    
     
		this.size=size; 
	}
	public synchronized void put(){
    
     //同步方法,实现存票的功能
		System.out.println("Producer puts ticket "+(++number));
		available=true;
	}
	public synchronized void sell(){
    
     //同步方法,实现售票的功能
		if(available==true && i<=number)
			System.out.println("Consumer buys ticket "+(++i));
		if(i==number) available=false;
	}
}
class Producer extends Thread{
    
    
	Tickets t=null;
	public Producer(Tickets t) {
    
    
		this.t=t;
	}
	public void run(){
    
    //如果存票数小于限定总量,则不断存入票
		while(t.number<t.size) t.put();
	}
}
class Consumer extends Thread{
    
    
	Tickets t=null;
	public Consumer(Tickets t){
    
    
		this.t=t; 
	}
	public void run(){
    
    //如果售票数小于限定总量,则不断售票
		while(t.i<t.size) t.sell();
	}
}

线程的生命周期

在这里插入图片描述

线程的几种状态:
诞生状态、就绪状态(start方法已被执行)、运行状态、阻塞状态(发出请求且必须等待其返回,遇到synchronized但不能使用时)、休眠状态(sleep方法)、死亡状态(线程已完成或退出)

猜你喜欢

转载自blog.csdn.net/Luminous_song/article/details/111060034