IO流
文件操作:
使用java.io.File类来创建一个文件对象
File file = new File(文件绝对路径);
File对象的常用方法:
exists(): 判断文件是否存在,返回boolean类型
isFile(): 判断是否为文件,返回boolean类型
isDirectory(): 判断是否为文件夹,返回boolean类型
getPath(): 得到文件的相对路径,返回String类型
getAbsolutePath():得到文件的绝对路径,返回String类型
getName(): 获得文件的文件名,返回String类型
length(): 获得文件的字节大小,返回long类型
delete(): 删除文件或文件夹,返回boolean类型
createNewFile():创建一个文件
mkdir(): 创建一个文件夹
listFiles(): 获取文件夹中的所有文件【包含子文件夹】
流:流是指一连串流动的字符,是以先进先出方式发送信息的通道,所有的流都是java.io包下面的
流是用来传输数据的,文件读取也是传输数据的一种方式。
流的分类:
按流向划分:输入流/输出流(这里的输入流与输出流是相对于内存而言)
按内容划分:字符流/字节流(字节流是1个字节8位,字符流是2个字节16位)
按形式划分:实体流/装饰流(实体流可以直接处理数据源,装饰流必须要与其他实体流结合起来才能使用)
字符流:
通常都是继承自Reader类和Writer类,一个是读,一个是写,常用的子类是FileReader和FileWriter
字节流:
通常是继承InputStream类与OutputStream类,一个是输入流,一个是输出流,常用的子类有FileInputStream、FileOutputStream
这里大家需要死记住一个点:
流是成对出现的,它们的子类也是成对的,很少会出现单个,比如:
InputStream OutputStream
Reader Writer
FileReader FileWriter
BufferedReader BufferedWriter
DataInputStream DataOutputStream
使用流读文件:
//第一步:创建输入流
InputStream input = new FileInputStream(文件对象或文件路径字符串);
//第二步:读文件
byte[] bytes = new byte[1024]; //每次读取1KB,大小可以自己设
StringBuffer s = new StringBuffer(""); //用来存储读取出来的数据
int len = input.read(bytes); //读文件,返回读到的长度
while(len >= 0){ //循环,如果长度>=0,说明读到了内容
//将读到的内容放到事先准备的字符串里
s.append(new String(bytes,0,len));
len = input.read(bytes); //继续读
}
//第三步:关闭流
input.close();
System.out.println(s.toString());
使用流写文件:
//第一步:创建输出流
OutputStream output = new FileOutputStream(文件对象或是文件路径字符串);
//第二步:写文件
String content = "内容...";
output.write(content.getBytes());
//第三步:清空缓存并关闭流
output.flush();
output.close();
使用字节流读写文件与上类似,如果是读,则先创建Reader对象,如果是写则先创建Writer对象,然后分别调用read()方法或是write()方法即可。
String类的用法
扩展:
一.equals和==区别
1.equals比较的是内容是否相等
2.==比较的是地址是否相等
3.注意:如果字符串是常量则在常量池中保存,再创建一个常量,先去常量池找,如果存在则直接指向,所以地址相同
二.字符串的常用方法
1.length():获取长度
2.equals():比较两字符串是否相等
3.equalsIgnoreCase():忽略大小写比较是否相等
4.toUpperCase():转大写
5.toLowerCase():转小写
6.trim():去字符串左右两边的空格
7.indexOf():获取第一次出现的位置,从0数
8.lastIndexof():获取最后一次出现的位置
9.indexOf(参数1,参数2):参数1:要查找的对象
参数2(int类型):从哪里开始找
9.substring(int a,int b):截取字符串
a:从什么位置开始截取(从0数)
b:到什么位置结束(从1数)
10.trim():去字符串左右两边的空格
11.split(String a):拆分
a:通过a字符来拆分,拆完后返回String[]类型
三.StringBuffer:是String的增强版
a.创建:StringBuffer 变量名=new StringBuffer(值);
b.append():连接,追加(直接在原件上追加)
String的concat():在副本上追加,原件不发生变化
例:String str="aa";
str.concat("bb");
输出str的结果:aa
c.StringBuffer和String互相转换
将String转StringBuffer
StringBuffer sb =new StringBuffer("值");
将StringBuffer转String
String ss=sb.toString();
d.insert(int index,object obj):在指定的index位置插入字符;(第一个参数,指定的位置,第二个参数插入的字符)
变量和数据类型
基本数据类型:int short long float double char boolean byte
引用数据类型:String 数组 类
带参数的方法
一、参数
1.参数列表(形参)前面需要加数据类型
public void addName(String name,String name1,...){....}
2.调用的时候是传递实参,实参列表无需加数据类型
stu.addName("TKK","",....);
3.实参列表和形参列表的数量要一致
4.实参列表和形参列表数据类型要一一对应
5.实参列表和形参列表的顺序要保持一致
二、包
1.作用:a.管理文件
b.解决文件的命名冲突,同一个项目中两个相同的文件可以存在不同的包中
c.保护包中的文件(要使用不同包中的文件,必须要先导入包)
2.创建包:package 包名;
3.导入包:import 包名.类名;
4.包的命名规范:a.不能以圆点(.)开头或结尾
b.包名必须是小写
c.域名倒置(com.baidu.www
cn.部门名.项目名)
三.方法的四种类型
1.无参无返回
public void show(){}
2.无参有返回
public boolean get(){ return false;}
3.有参无返回
public void show2(Student stu){}
4.有参有返回
public int show3(int[] score){}
多态
1、多态
多态的概念:同一种事物,由于条件不同,产生的结果也不同。
实现多态的两个要素:
1、必须要有父子继承关系,子类重写父类的方法。
2、使用父类的类型,子类的对象【父类的类型指向子类对象】
实现多态的两种形式:
1、使用父类作为方法形参实现多态。
2、使用父类作为方法的返回值实现多态。
多态的核心理念:静态编译,动态绑定
静态编译:是指程序在编译的时候是按照父类的类型来编译的。
动态绑定:是指程序在运行的时候传的参数却是子类对象。
2、引用数据类型的转换:
向上转型时可以自动转换(子类可以自动转换成父类)
向下转型时需要强制转换(父类必须强制才能转换成子类)
自动转型例子: Pet pet = new Dog(); Dog类是Pet类的子类,所以可以直接赋值给父类对象
强制转型例子: Dog dog = (Dog)pet; pet是dog的父类,不能直接赋值,必须强转
instanceof运算符:判断左边的对象是否属于右边的类型,返回true和false,语法为
boolean flag = 对象名 instanceof 类名/接口名;
boolean flag = dog instanceof Pet; 注意左边的dog是对象名,右边的Pet是类名
3、方法重载:
简而言之:方法同名不同参。
满足方法重载的几个条件:
1、必须是在同一个类里面。
2、方法名必须相同。
3、参数列表必须不同(参数个数,参数类型,参数顺序)
4、方法重载和访问修饰符、返回值类型、抛出异常没有关系。
@Overload 该注解可以用来检查方法是否满足重载条件。
重载与重写的区别:
1、方法重写是发生在父类与子类之间,而方法重载只在同一个类里面进行。
2、方法重写是子类为扩展父类方法的功能而编写的方法,重写要求:
a、方法名相同
b、参数列表相同
c、返回值类型相关
d、访问修饰符只能大于等于父类方法的范围
e、子类抛出的异常只能是父类抛出的异常或它的子异常。
3、方法重载是为了方便对一个操作提供多种方案而编写的方法,重载要求:
a、方法名相同
b、参数列表不同
c、跟返回值类型、访问修饰符、抛出的异常没关系。
重载和重写都是多态的表现形式。
多线程
进程与线程的概念:
进程:一个应用程序的实例【一个程序就是一个进程】
线程:cpu调度的基本单位【一个线程就是一条单独的执行过程,一个进程至少会有一个线程(主线程)】
多线程:
是指在一个应用程序中(在一个进程中),同时运行了多个线程,用来完成不同的工作,就称之为多线程。
【注意:多线程其实是多个线程交替占用CPU的资源,而非真正的并行执行】
CPU在多个线程之间切换速度非常快,用户感觉不出来,以为是在同时执行,其实【CPU在同一时间只能执行一条线程】
自己想象多台电脑使用同一个路由器上网的例子。
使用多线程的好处:
1、充分利用了CPU的资源
2、给用户带来良好的体验
3、简化编程模型
java.lang.Thread类:
线程类,该类的静态currentThread()方法可以获取【当前】正在执行的线程的对象,返回Thread对象。
该类的方法setName(String name)与getName()可以用来设置和获取线程的名称。
Main线程:
程序的主线程,每个程序,只要main方法一运行,就会自动产生一个main线程
【如果程序没有用多线程,无论main方法里面写了多少代码、创建了多少个对象、调用了多少个方法,始终只会有一个线程】
在main线程中启动的线程称之为子线程。
实现多线程的两种方式:
1、继承Thread类
a、重写run方法
b、创建线程对象
c、启动线程
2、实现Runnable接口
a、实现run方法
b、创建接口的对象
c、创建线程对象【把接口的对象当作构造方法的参数传入】
Thread t = new Thread(接口的对象);
d、启动线程
【注意启动线程是用线程的对象.start()方法,而非.run()方法】
线程的几种状态
1、创建状态:Thread对象被new出来时,还没有启动,则处于创建状态。
2、就绪状态:Thread对象调用了start()方法启动了,但是该线程并没有获取CPU的资源时,处于就绪状态。
3、运行状态:Thread对象获取了CPU的资源,开始执行run()方法里面的代码时,处于运行状态。
4、阻塞状态:Thread对象在执行run()方法的过程中,如果遇到需要等待的情况【卡顿】,则线程处于阻塞状态。
【解除阻塞后,该线程会进入就绪状态而非运行状态】
5、死亡状态:Thread对象的run()方法中的代码全部执行完,该线程就会处于死亡状态,线程被销毁。
【线程总是在就绪与运行状态之间来回切换,获取CPU资源时运行,交出CPU资源时就绪,但是也会有进入阻塞的情况】
Thread类的常用方法:
静态方法:
1、currentThread():静态方法,用于获取当前正在执行的线程的对象。
2、sleep():设置线程休眠指定毫秒数。
非静态方法:
1、getName():获取线程的名称
2、setName():设置线程的名称
3、setPriority():设置线程的优先级【1-10】,参数是整数,数字越大,优先级越高
【优先级是指在分配CPU的资源时,优先级越高的,获取CPU的资源的几率越大】
4、getPriority():获取线程的优先级
5、join():让自己线程处于阻塞状态,让指定线程强制执行,等该线程执行完之后,解除自己的阻塞状态
6、yield():实现线程的礼让。
【让自己线程处于就绪,让出cpu的资源,然后让CPU重新分配资源】
【yield只是提供一个礼让的可能,但并不能保证一定能实现礼让】
join()与yield()的区别:
join()是让自己线程进入阻塞状态,完全不参与CPU资源的争取
yield()是让自己处于就绪状态,还是有可能再次分配到CPU的资源的。
synchronized关键字:
可以修饰代码块,称为同步代码块
可以修饰方法,称为同步方法
【凡是加上了synchronized关键字的代码块、方法,在同一时间,只会有一个线程能进入到代码块里面执行,其他调用的线程需要等待】
【一个对象里面,如果某个线程在调用该对象一个同步方法,那么该对象的其他同步方法也会被锁定】
【一个对象里面,如果某个线程在调用该对象一个同步方法,那么该对象的其他非同步方法可以被其他线程调用】
面向对象编程的特性
抽象、封装、继承、多态,其中封装、继承和多态是核心。
抽象:让事物脱离具体化,只将它的类型、属性和行为抽离出来形成一个类,例如针对猫、狗、牛、羊,根据它们的共同特征和共同行为,可以把它们抽象出一个动物类,这个从现实中的物体到程序的类设计就是一个抽象的过程,动物类本身就是泛指,它不指具体的某一种动物,这就是脱离具体化的体现。
构造方法:
用途:让对象在初始化时,给对象的属性赋初始值,构造方法在实例化对象时自动调用。
特点:
1、方法名与类同名,必须完全一模一样。
2、没有返回值类型,连void都不要写。
语法:
访问修饰符 方法名(参数列表){
//方法体
}
构造方法的重载的条件
1、重载的两个方法,方法名必须一模一样(都是类名)。
2、参数列表不一样(参数个数、类型、排列顺序不一样)。
3、与访问修饰符没有关系。
注意:系统默认为每一个类提供了一个无参的构造方法,如果程序员手动写了一个以上的构造方法,那么系统默认的无参构造方法就会无效。
static关键字
static是静态的意思,它可以用来修饰属性和方法,作用如下:
修饰属性时,该属性为静态属性,可以直接通过类名.属性名操作,且所有对象共享。
修饰方法时,该方法为静态方法,可以直接通过类名.方法名调用。
注意:
1、静态变量只能写在方法外面,不能写在方法里面
2、不能在静态方法中直接用this调用同类的其他非静态方法或属性。
静态代码块:写在方法外的单独代码块,它会在类的字节码加载到虚拟机时执行(比构造函数还早)
语法:
static{
}
静态代码块的作用通常是在类加载时(不是实例化)需要做一些初始化的操作,比如读取配置文件等。
封装:
简而言之就是隐藏内部的实现细节,对外提供接口的这样一种设计,封装可以增强代码的安全性
封装是通过访问修饰符来进行控制的。
封装的实现步骤:
1、属性设为私有的,这样就无法在其他类直接通过对象名.属性名来直接操作该属性
2、提供对外的接口,每一个属性提供一个getter方法和setter方法来访问该属性
3、在getter、setter方法中增加逻辑控制语句。
shift + alt + s + r:快速写getter/setter方法
shift + alt + s + o:快速写构造方法
集合框架
有了数组为什么还需要集合框架:
数组的弊端:类型必须相同、长度是固定的,如果一组数据在程序运行时并不能确定长度,那就不能再使用数组了。
相对于数组,集合框架不限类型,并且长度可变,运用更加灵活。
java.util包下的两个集合上级接口:
1、Collection:存储单个对象的集合,特点:无序,不唯一,它有两个子接口:
List:有序、不唯一,常用的方法有:
添加对象:add(obj)、add(int index,Object obj)
按对象移除对象:remove(obj)
按下标移除对象:remove(index)
获取对象:get(index)
获得集合长度:size()
查看集合中是否包含某个对象:contains()
典型的实现类有:
ArrayList:以数组的方式来存储,查询效率高,插入和删除效率低
LinkedList:以链表的方式来存储,查询效率低,插入和删除效率高,LinkedList有扩展的方法:addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast()
Set:无序、唯一,典型的实现类有:
HashSet:以哈希表的形式存储
TreeSet:以树形表的形式存储
2、Map:存储键值对的集合,键key,值value,键与值是一一对应的,常用的方法有:
put(key,value):往Map中增加一个键值对
get(key): 根据key获取值
remove(key): 根据key,将这一个键值对移除掉
size(): 获取集合的长度
keySet():获取键的集合,返回的是一个Set对象(这也说明了为啥key不能重复)。
values():获取值的集合,返回的是一个Collection对象,(这也说明了为啥value可以重复)
containsKey(): 判断map中是否包含了某个键
Map的键是唯一的,但值不唯一。
迭代器Iterator:
迭代器对象可以用来迭代集合,它的常用方法是:
hasNext():判断是否还有下一个元素,返回boolean类型的值,通常用来做循环的条件。
next(): 获取下一个元素,返回Object类型的对象
Collection接口继承了Iterator接口,所以它有一个方法叫iterator(),该方法的作用就是拿到集合的迭代器对象
foreach循环:
语法:
for(类名 对象名 : 集合){
}
泛型集合:
使用泛型集合的好处
1、在插入元素会有数据类型的检查,如果数据类型不一致会编译报错
2、在取元素的时候不需要强制类型转换
语法例子:
List<Dog> list = new ArrayList<Dog>:只有Dog类的对象才能加入到list中
Map<String,Penguin> map = new HashMap<String,Penguin>();
这个map集合的键只能是String类型的,而value只能是企鹅,如果不按规定添加就报编译错误
注意:jdk1.5以上的版本都支持泛型,但之前的版本不行
Vector与ArrayList的区别:
Vector的线程安全,但效率低,ArrayList的线程不安全,但效率高
HashMap与Hashtable的区别
HashMap允许插入空键,Hashtable不能插入空键
Hashtable的线程安全,但效率低,HashMap的线程不安全,但效率高
继承
继承:
使用关键字extends来继承一个类,被继承的类成为基类(父类),而继承的类称为子类。
在java中,只能单根继承,即只能继承一个父类,不能同时继承多个父类。
不能继承用final修饰的类,比如java.lang.String类就是用final修饰的,不能被继承。
继承时,子类将继承父类的所有属性和方法,但不包括如下情况:
1、不能继承构造方法
2、不能继承父子类不在同一包下,使用默认访问修饰符修饰的属性和方法
3、不能继承私有的(private修饰)属性和方法
在子类中调用父类的属性和方法时,使用super关键字点属性或点方法,在子类的构造函数中,默认会有一行代码:super(),表示默认会先调用父类的无参构造方法,这行代码写与不写,程序始终都会执行父类的无参构造方法。
实例化子类的程序执行过程1(不包括静态成员):
父类属性 > 父类构造方法 > 子类属性 > 子类构造方法
实例化子类的程序执行过程2(包括静态成员)
父类的静态成员与静态代码块 > 子类的静态成员与静态代码块 > 父类的属性 > 父类的构造方法 > 子类的属性 > 子类的构造方法
访问修饰符:
java中的4种访问修饰符用来控制类、对象、属性的访问权限,以下是4个访问修饰符在4种不同位置是否可以访问。
修饰符 本类 同包 子类 其他
public 是 是 是 是
protected 是 是 是 否
默认(不写) 是 是 否 否
private 是 否 否 否
访问修饰符范围大小:public > protected > 默认 > private
死记住规则:public的范围最大;private的范围最小;protected同包父子类;默认修饰符只同包。
方法重写:是指父类的方法不能满足子类的需求,子类重写父类的方法体,重写的规则如下:
1、重写必须在继承的前提条件下进行
2、子类重写的方法名与参数列表必须与父类的方法名参数列表完全一致。
3、子类方法的访问修饰符必须大于等于父类方法的访问范围
4、子类方法的返回值必须与父类的返回值相关(返回基本数据类型时子类必须与父类完全一样,返回引用数据类型时,子类的返回值类型与父类的返回值类型相同,或是父类的返回值类型的子类)
@Override:@符号开头的称为注解,该注解是重写的注解,表示该方法为重写方法,如果方法不满足重写规则,使用该注解时编译会报错,编码时,可以用此注解来检查重写方法是不是写错了。
抽象类:使用abstract修饰的类称之为抽象类,语法:
public abstract class 类名{
}
抽象类中可以包含抽象方法,也可以包含非抽象方法,抽象方法也使用abstract修饰
public abstract void show();
注意事项:
1、抽象类不能被实例化,所以抽象类需要有类来继承,否则写抽象类就没有任何意义。
2、抽象方法必须写在抽象类里。
3、抽象方法不能有方法体,连大括号都不能有。
4、抽象方法必须被子类重写,除非子类也是一个抽象类。
5、抽象类的abstract不能与final、static关键字同时存在。
abstract与final的区别:
abstract可以用来修饰类和方法,final可以用来修饰类、属性、方法。
abstract修饰类时,表示该类为抽象类,不能实例化,需要被子类继承。
final 修饰类时,表示该类为终极类,不能被继承。
abstract修饰方法时,表示该方法为抽象方法,不能有方法体,必须被子类重写,除非子类也是抽象类。
final 修饰方法时,表示该方法为终极方法,不能被重写。
final 修饰属性时,表示该属性为终极属性,必须赋初始值,并且不能修改属性的值。
抽象方法不能static同时存在的原因,static修饰的方法表示不需要实例化就可以直接通过类名.方法名来进行调用,但是抽象方法并没有方法体,所以它们之间是不允许同时存在的。
接口
接口
1、接口的概念:提供一种规范、表示一种能力。
2、生活中的接口:
具可以参照现实生活中的插线板,插线板就是一个接口的典型例子,它提供了一种规范和能力。
插线板提供的规范:规定了插孔的个数(三孔、两孔)
插线板提供的能力:可以让电器通电
所有电器的插头要实现插线板的接口就必须遵守这个规范:插头都必须做成三脚或两脚的,实现后电器具备了通电的能力。
接口只负责提供规范和能力,但它本身却并没有实现具体功能,具体功能由实现这个接口的实现类来实现。
比如USB接口本身没有任何功能,如果没有外部设备插入,它什么也干不了,而具体做什么是取决于连上什么设备,连上鼠标可以使用鼠标来控制界面,连上U盘可以存储读写数据,所以接口的具体功能是由它的实现方来提供的。
3、java里的接口:
使用interface关键字修饰,语法为:
访问修饰符 interface 接口名{
}
4、实现接口:
1、子类与父类的关系称之为继承,子类与父接口之间的关系称之为实现。
2、使用implements关键字来实现接口
3、java中一个类可以实现多个接口(多继承)
接口的特点:
1、接口不能被实例化。
2、接口中所有的方法都是抽象方法,不能包含实例方法,且访问修饰符必须为public,写与不写都是public。
3、接口中可以包含属性,但是只能是公有的静态常量,public static final可以省略,写与不写都只能是public static final
4、子类实现接口必须重写接口中的所有方法。
5、接口可以继承接口。
接口与抽象类的异同:
相同点:都不能被实例化,都可以包含抽象方法,都可以包含静态常量。
不同点:
抽象类:使用abstract修饰的类,有构造方法,可以包含非抽象方法并且可以是非public的,可以包含非public的普通变量。
接口:使用interface关键字声明,没有构造方法,不能包含非抽象方法,且所有方法必须是public的,只能包含public的静态常量。
重点:
父类与子类的关系是is-a的关系,表示什么是一个什么。例如:狗继承宠物类,表示狗是一只宠物
接口通常都是表示子类具备某种能力,接口与实现类之间是has-a的关系,表示什么可以做什么。例如:防盗门实现了锁的接口,说明防盗门可以上锁了,但是不能说防盗门是一把锁
类的无参构造
一.无参方法(有返回,无返回的方法)
1.定义:对象具有的行为,操作
2.包含:访问修饰符(public) 返回类型(void,String,int,等数据类型) 方法名 主体
3.返回类型:
a.无返回:void
b.有返回:return 变量;
二.常见错误
1.void 和return不能共存
2.不能返回多个值
3.方法不能嵌套
4.逻辑代码必须放入方法中
三.方法的调用
1.不同的类:创建对象,对象名.方法名();
2.同一个类:直接写 方法名();
四.局部变量和成员变量
1.局部变量定义在方法里面
只能用在方法里面,其他地方不能使用
2.成员变量定义在类里面,方法外面
整个类中都可使用
3.成员变量不赋初始值,有默认值
String:null int:0 double:0.0 char:空格 boolean:false
局部变量不赋初始值,没有默认值
4.成员变量和局部变量可以同名,优先使用局部变量(就近原则)
同一个方法中:局部和局部不能同名,同一个类中:成员和成员不能同名
五.文档注释:/** 注释内容 */
导出文档:右击->export->java->javadoc->next->选中要导出的文件 ->finish
创建方法:
public 数据类型 方法名(){
return ;
}
调用方法
同一个类: 数据类型 变量名=方法名();
不同类:类名 对象名=new 类名();
数据类型 变量名=对象名.方法名();
Object Oriented Programming 面向对象的编程(OOP)
类和对象
一.对象:由一组属性和方法构成(看得见摸得着,真实存在)
1.属性:对象具有的静态特征(可以用语言来描述的)
2.方法:对象具有的行为,操作(动态特征)
3.封装:尽量隐藏内部细节(包装)
安全,保护的作用
使用时无需知道内部细节,只要会用
二.类:创建一组属性和方法的对象的集合(抽象的)
三.类和对象的关系
类是对象的抽象
对象是类的实例
四.使用类的步骤:
1.创建类:public class 类名{}
2.创建属性
3.创建方法:
访问修饰符(public) 返回类型(void) 方法名(){}
五.创建对象的步骤:
1.创建对象:类名 对象名=new 类名();
2.调用属性:对象名.属性名=值;
3.调用方法:对象名.方法名();
六.面向对象的优点:
1.符合人类思维方式(分类的方式)
2.代码复用(创建一次,可重复使用)
3.安全和提高可维护性
循环结构
一.循环:重复的做同一件事情
1.while语法:先判断,再执行
初始化循环变量;
while(循环继续条件){
循环操作;
更新循环变量;
}
2.使用步骤(做题思路)
a.找4个条件
初始化循环变量 循环条件 循环操作 更新循环变量
b.套用语法
c.检查是否能够跳出循环
二.调试步骤:使程序停在设置断点的地方,单步执行以便查找错误
1.在可能出现错误的地方设置断点
2.启动调试(debug)
3.单步执行(F6)
4.观察变量的变化,并找出错误
三.do-while循环:先执行,再判断
1.语法:
初始化循环变量
do{
循环操作;
更新循环变量;
}while(循环条件);
2.while和do-while异同
相同:都执行循环操作
不同:a.执行顺序:while先判断再执行
do-while先执行再判断
b.语法:while循环后是'{}'
do-while循环后是';'
c.初始条件不成立,while一次也不执行操作
do-while至少执行一次操作
一.for循环:用于循环次数固定时
1.语法:
for(1.初始化循环变量;2.循环条件;3更新循环变量){
4.循环操作;
}
2.执行顺序:1 ,2 ,4, 3
3.注意:
a.初始化循环变量既可以放入小括号里面,也可以放入for的上面
b.少条件,造成死循环
c.少更新循环变量,造成死循环,更新循环变量可以放入操作下面
d.如果三个表达式都没有,死循环
二.break和continue
1.break:可以使用到while,do-while,for循环中。遇到break跳出整个循环
2.continue:只能用于循环中,遇到continue结束本次循环,继续下一次循环(用continue,取反)
异常
异常是指程序在运行的过程中出现了无法预料的错误。
针对异常有两种解决方式:
1、捕获处理方式:
try{
//可能会出现异常的代码块
}catch(异常的类名1 对象名){
//捕获异常1时执行的代码块
}catch(异常的类名2 对象名2){
//捕获异常2时执行的代码块
}finally{
//始终都会执行,并且在最后执行的代码块
}
注意
1、try不能单独存在,它必须与catch或finally一起使用。
2、catch可以写多个,但是通常按异常从小到大来进行catch,这里的大小是指异常类的父子关系,比如Exception类就是最大的,而NullPointerException则是Exception的子孙类,所以在catch异常的时候,应当把Exception放在最后面。
3、程序出异常时只会进满足条件的第一个catch块。
4、finally是始终都会执行的部分,不管有没有发生异常、有没有catch住异常,它都会执行,除非遇到了System.exit()这句话。
常见的异常:
Exception:异常类,它是所有异常类的顶级父类。
RuntimeException:运行时异常
ArithmeticException:除零异常
ArrayIndexOutOfBoundsException:数组下标越界
NullPointerException:空指针异常
ClassNotFoundException:不能加载所需要的类
ClassCastException:对象强制类型转换异常
NumberFormatException:数字格式异常
finally、finalize、final的区别:
final用来修饰类、属性和方法,修饰类时,该类不能被继承;修饰属性时,该属性不能改变值;修饰方法时,该方法不能被重写
finalize:java的垃圾回收方法,可以清理内存中没用到的对象,注意:该方法不需要调用,因为java会自动检测并清理内存,简称为GC
finally:异常的一部分,表示始终都会执行
2、抛出处理方式:将异常往外抛出,不再用本类中的try-catch来处理,让调用该方法的那一方来处理
语法:在方法名的小括号后面、大括号前面加上 throws 异常类名1,异常类名2
throws:将异常往外抛出。
throw:人为制造出一个异常。比如代码 throw new Exception("程序崩溃啦!"); 系统执行到这一行代码的时候,就会产生一个人为的异常,人为的异常也需要抛出或者用try-catch来处理。
异常的分类:
1、编译异常【编译异常必须处理,否则编译不通过】
2、运行时异常【运行时异常可以不处理,但是程序报错时程序会停在报错的行】
使用Log4j的步骤:
1、导包(把jar包复制到项目里,并且添加到构建路径“右键jar包—Build Path—Add to build Path”)
2、创建并编写配置文件log4j.properties(写到src目录下)
3、创建Log4j对象(Logger log = Logger.getLogger(类名.class)、 Logger log = Logger.getLogger(类名.class.getName()))
4、调用一系列方法(log.info(提示信息字符串)、log.debug(调试的变量)、log.error(错误信息字符串))
properties文件是属性文件,它里面的内容是键值对,一个键对应一个值
好处:
java是后台程序,一般都是运行在服务器上,而服务器是不能用来调试代码的,只能拿到服务器的日志文件,从日志文件的内容来分析错误,log4j就是以不同的形式来记录日志的,方便开发人员分析日志