- 面向对象概述
- 面向对象的概念
- 面向对象是相对面向过程而言的。
- 面向过程:
- 强调的是功能行为。
- 面向对象:
- 将功能封装进对象,强调具备了功能的对象。
- 面向对象是基于面向过程的。
- 面向对象的特点
- 是一种符合人们思考习惯的思想,可以将复杂的事情简单化,将程序员从执行者转换成了指挥者。
- 完成需求时:
- 先要去找具有所需的功能的对象来用。
- 如果该对象不存在,那么创建一个具有所需功能的对象。
- 这样简化开发并提高复用。
- 先要去找具有所需的功能的对象来用。
- 开发的过程:
- 其实就是不断的创建对象,使用对象, 指挥对象做事情。
- 设计的过程:
- 其实就是在管理和维护对象之间的关 系。
- 面向对象的特征:
- 封装(encapsulation)
- 继承(inheritance)
- 多态(polymorphism)
- 封装(encapsulation)
- 是一种符合人们思考习惯的思想,可以将复杂的事情简单化,将程序员从执行者转换成了指挥者。
- 类与对象的关系
- 类与对象的关系概述
- 类就是对现实生活中事物的描述。
- 对象即是该类事物实实在在存在的个体。
- 类与对象的关系如图:
图纸就是类
汽车就是堆内存中的对象
- 类的定义
- Java中用类class来描述事物。
- 属性:对应类中的成员变量。
- 行为:对应类中的成员函数。
- 属性:对应类中的成员变量。
- Java中用类class来描述事物。
- 对象在内存中的结构
- 成员变量和局部变量
- 成员变量
- 成员变量定义在类中,在整个类中都可以被访问。
- 成员变量随着对象的建立而建立,存在于对象所在的堆内存中。
- 成员变量有默认初始化值。
- 成员变量定义在类中,在整个类中都可以被访问。
- 局部变量
- 局部变量只定义在局部范围内,如:函数内,语句内等。
- 局部变量存在于栈内存中。
- 作用的范围结束,变量空间会自动释放。
- 局部变量没有默认初始化值。
- 局部变量只定义在局部范围内,如:函数内,语句内等。
- 使用匿名对象的两种情况
- 当对对象方法仅进行一次调用的时
- 匿名对象可以作为实际参数进行传递
- 封装(Encapsulation)
- 概念
- 封装:是指隐藏对象的属性和实现细节,仅对外提供 公共访问方式。
- 封装:是指隐藏对象的属性和实现细节,仅对外提供 公共访问方式。
- 好处
- 将变化隔离。
- 便于使用。
- 提高重用性。
- 提高安全性。
- 将变化隔离。
- 封装原则
- 将不需要对外提供的内容都隐藏起来。
- 把属性都隐藏,提供公共方法对其访问。
- 将不需要对外提供的内容都隐藏起来。
- 函数是代码中最小的封装。
- private(私有)关键字
- 用于修饰成员(成员变量和成员函数)。
- 被私有化的成员只在本类中有效。
- 开发中通常将成员变量私有化,再对外提供对应的set ,get 方法对其进行访问,以提高对数据访问的安全性。
- 私有仅仅是封装的一种表现形式。只要是程序访问不到的都是封装的表现。
- 用于修饰成员(成员变量和成员函数)。
- 构造函数
- 构造函数的特点
- 函数名与类名相同。
- 不用定义返回值类型。与void不同,void也是一种返回类型。
- 不可以写return语句。
- 函数名与类名相同。
- 构造函数的作用
- 对象一建立就会调用与之对应的构造函数。构造函数用于给对象进行初始化。
- 构造函数的其它细节
- 当一个类中没有定义构造函数时,系统会默认给该类加入一个空参数的构造函数。
- 当在类中自定义了构造函数后,默认的构造函数就没有了。
- 多个构造函数是以重载的形式存在的。
- 构造函数和一般函数的比较:
- 构造函数在对象一建立时就运行,给对象初始化。
- 一般函数在对象调用时才执行,给对象添加对象具备的功能。
- 一个对象建立,构造函数只运行一次,而一般函数可以被该对象调用多次。
- 构造代码块
- 也用于给对象进行初始化。
- 对象一建立就运行,且优先于构造函数执行。
- 构造代码块中定义的是不同对象共性的初始化内容,是给所有对象进行统一初始化。而构造函数是给对应的对象进行初始化。
- this关键字
- 概述
- this代表其所在函数所属对象的引用。
- 用途
- 当在函数内需要用到调用该函数的对象时,就用this。例如用于区分同名的成员变量和局部变量。
- this语句可以用于构造函数之间的相互调用。this语句只能定义在构造函数的第一行,即先进行this语句的初始化。
- static(静态)关键字
- 概述
- static只能修饰成员(成员变量,成员方法),不能修饰局部变量。
- 当成员被static修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用:类名.静态成员
- 静态成员存放在内存的方法区中。
- 非静态成员变量也叫实例变量,静态成员变量也叫类变量。
- 主函数就是静态函数里面实例化类的对象后再调用非静态成员函数的例子。
- static特点:
- 随着类的加载而加载,随着类的消失而消失。
- 优先于对象存在。
- 被所有对象所共享。
- 可以直接被类名调用。
- 随着类的加载而加载,随着类的消失而消失。
- static只能修饰成员(成员变量,成员方法),不能修饰局部变量。
- 实例变量与类变量的比较
- 存放位置:
- 类变量随着类的加载而存在于方法区中。
- 实例变量随着对象的建立而存在于堆内存中。
- 生命周期
- 类变量生命周期最长,随着类的消失而消失。
- 实例变量生命周期随着对象的消失而消失。
- 存放位置:
- static的注意事项
- 静态方法只能访问静态成员。
非静态方法既可以访问静态成员也可以访问非静态成员。
- 静态方法中不可以写this,super关键字。因为静态优先于对象存在。
- 静态方法只能访问静态成员。
- static的优缺点
- 好处:
- 对对象的共享数据进行单独空间的存储,节省空间。
- 可以直接被类名调用。
- 弊端:
- 生命周期过长。
- 只能访问静态成员,访问具有局限性。
- 好处:
- main函数
- 主函数是一个特殊的函数,作为程序的入口,是固定格式的,可以被JVM调用。
- 主函数的定义:public static void main(String[] args)
- public:代表该函数的访问权限是最大的。
- static:代表主函数随着类的加载就已经存在了。
- void:主函数没有具体的返回值。
- mian:不是关键字,但是是一个特殊的单词,可以被JVM识别。
- String[] args:主函数的参数,参数类型是一个字符串类型的数组。
- JVM在调用主函数时,默认传入的参数是new String[0],也可以给主函数传入其它参数。
- static的使用时机
- 静态变量:
- 如果在定义一个类的时候,发现一个成员变量需要被所有实例所共享,那么这个成员变量就需要定义为static的。
- 如果在定义一个类的时候,发现一个成员变量需要被所有实例所共享,那么这个成员变量就需要定义为static的。
- 静态方法:
- 如果一个方法不用访问对象的非静态成员,那么就可以定义为静态的,这样使用者就不需要创建对象,直接用类名调用。
- 静态方法通常是作为工具方法或者一个可以产生对象的方法被声明,目的是为了让调用者更方便的使用,不必创建对象。
- 如果一个方法不用访问对象的非静态成员,那么就可以定义为静态的,这样使用者就不需要创建对象,直接用类名调用。
- 静态变量:
- 静态的应用-工具类
- 工具类里的方法并没有使用到类的成员变量,所以类的方法都可以定义为静态的。
- 防止用户创建对象的做法:构造函数私有化
- 帮助文档的制作javadoc
- 使用文档注释修饰一个类的源代码之后可以通过javadoc.exe来生成帮助文档。
- 生成文档的命令:
- javadoc -d (目录) -version –author (源文件)
- javadoc -d (目录) -version –author (源文件)
- 批注参数来标记一些特殊的属性及其相应的说明:
- @author<作者姓名>
- @version<版本信息>
- @param<参数名称><参数说明>
- @return<返回值说明>
- @author<作者姓名>
- 举例:
- javadoc -d mydoc -author -version MyDemo.java
- 静态代码块
- 格式:
- 静态代码块在类加载后执行。静态代码块优先于主函数执行。
- 静态代码块和静态方法相同,不能使用外部非静态成员。
- 静态代码块执行和静态变量的初始化顺序由代码从上到下顺序决定。
- 定义某个类的空变量不会加载该类,具体用到类的内容时,该类才会被加载到内存中。
- 格式:
- 对象的初始化过程
- 类文件加载->执行类的静态代码块->开辟内存空间建立对象->非静态属性默认初始化->非静态属性显示初始化->执行构造代码块->构造函数初始化->将内存地址赋给栈内存中的变量
- 类文件加载->执行类的静态代码块->开辟内存空间建立对象->非静态属性默认初始化->非静态属性显示初始化->执行构造代码块->构造函数初始化->将内存地址赋给栈内存中的变量
- 单例设计模式
- 设计模式
- 解决某一类问题的最行之有效的办法。
- 单例设计模式
- 保证一个类在内存只存在一个对象。
- 实现方法:
- 将构造函数私有化。
- 在类中创建一个本类对象。
- 提供一个方法用于获取该对象。
- 实现代码:
public class Single { private Single(){} private static Single s = new Single(); public static Single getInstance(){ return s; } }
- 注意:实际开发时,对于事物的描述不受任何影响。当需要保证该事物的对象在内存中唯一时,只需将上面三步代码加上即可。
- 单例设计模式的两种实现方式:懒汉式和饿汉式
- 饿汉式:类一被加载进内存,对象就创建好了。
public class Single { private Single(){} private static Single s = new Single(); public static Single getInstance(){ return s; } }
- 懒汉式:getInstance方法被调用时,对象才初始化,也叫做对象的延时加载。
由于每次进入getInstance方法都要判断锁,影响了程序的效率,因此可以做些改进:public class Single { private Single(){} private static Single s = null; public static synchronized Single getInstance(){ if (s == null) { s = new Single(); } return s; } }
public class Single { private Single(){} private static Single s = null; public static Single getInstance(){ if (s == null) { //如果s为null,才进行锁判断 synchronized (Single.class) { //进入锁后再次进行判断s是否为null //避免前面进入锁的线程已经创建了对象 if (s == null) { s = new Single(); } } } return s; } }
- 饿汉式是线程安全的,不需要上锁。而懒汉式存在线程安全问题,需要上锁。
- 实际开发中,建议使用饿汉式。
- 饿汉式:类一被加载进内存,对象就创建好了。
- 继承
- 继承的概述
- 多个类中存在相同属性和行为时,将这些内容抽取到 单独一个类中,那么多个类无需再定义这些属性和行 为,只要继承单独的那个类即可。
- 在程序中,可以使用extends关键字可以让一个类继承另外一个类。
- 继承的类为子类(派生类),被继承的类为父类(超类, 基类)。
- 子类可以直接访问父类中的非私有的属性和行为。
- 继承的好处:
- 继承的出现提高了代码的复用性。
- 继承的出现让类与类之间产生了关系,提供了多态的前提。
- 继承的出现提高了代码的复用性。
- 注意:不要为了获取其他类的功能简化代码而使用继承。类与类之间有所属关系才可以继承。所属关系:is a。
- 多个类中存在相同属性和行为时,将这些内容抽取到 单独一个类中,那么多个类无需再定义这些属性和行 为,只要继承单独的那个类即可。
- 继承的特点
- Java只支持单继承,不支持多继承。
- 因为当多个父类中定义了相同功能,当功能内容不同时,子类对象不确定要运行哪一个。
- 但是java保留了这种机制,并用另一种体现形式来表示:多实现。
- Java支持多层继承(继承体系)。
- 想要使用体系,要先查阅体系父类的描述,因为父类中定义的是该体系中的共性功能。通过了解共性功能,就可以知道该体系的基本功能。
- 实际开发中,查阅父类功能,创建最子类的对象使用功能。因为:
- 有可能父类不能创建对象。
- 创建子类对象可以使用更多的功能,包括基本的和特有的。
- Java只支持单继承,不支持多继承。
- 子类与父类的关系
- 子类与父类的关系
- 子父类中变量的特点:
- 如果父类中出现非私有的与子类同名的成员变量:
- 子类要访问本类中的变量,用this。
- 子类要访问父类中的同名变量,用super。
- super的使用和this的使用几乎一致。
- this代表本类对象的引用。
- super代表父类对象的引用。
- 如果父类中出现非私有的与子类同名的成员变量:
- 子父类中函数的特点:
- 当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容,如同父类的函数被覆盖一样。这种情况是函数的另一个特性:重写(覆盖)。
- 重写要求子类权限大于等于父类权限,否则编译失败。
- 静态只能覆盖静态。
- 重写方法的返回类型必须与原方法的返回类型相同或者符合多态的关系。
- 父类中的私有方法不可以被覆盖。
- 在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。
- 子父类中构造函数的特点-子类实例化过程:
- 子父类的构造函数间不存在覆盖关系。
- 子类中所有的构造函数默认都会访问父类中空参数的构造函数,子类每一个构造函数的第一行都有一条默认的语句 super()。
- 子类构造函数也可以显式地调用父类的其它构造函数。
- 子类会具备父类中的数据,所以要先明确父类是如何 对这些数据初始化的。当父类中没有空参数的构造函数时,子类的构造函数 必须通过this或者super语句指定要访问的构造函数。
- this语句和super语句不能同时存在于一个构造函数中(包括显式和隐式)。
- 子父类中变量的特点:
- final关键字
- final可以修饰类,方法,变量(成员变量、局部变量)。
- final修饰的类不可以被继承。
- 继承的出现打破了封装性,为了避免被子类覆写功能,可以用final修饰该类。
- final修饰的方法不可以被覆盖。
- 如果类中的部分类不希望被覆盖,可以单独将这些方法被final修饰。
- final修饰的变量是一个常量。只能被赋值一次。
- final标记的成员变量必须在声明的同时或者在该类的构造函数中显式赋值,才能使用。
- 当在描述事物时,一些数据的值是固定的。这时为了增强阅读性,可以给这个值起个名字,而这个值不需要改变,所以加上final修饰。
- 通常定义常量时,使用public static final功能标记该常量,这样常量就成了全局的常量。
- 这样定义的常量只能在定义时赋值,即使在构造函数中也不能对其进行赋值。
- 内部类只能访问被final修饰的局部变量。
- final可以修饰类,方法,变量(成员变量、局部变量)。
- 抽象类
- 抽象类概述
- 抽象就是从多个事物中将共性的,本质的内容抽取出来。
- 抽象方法的由来:
- 多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功 能声明,没有功能主体的方法称为抽象方法。
- 多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功 能声明,没有功能主体的方法称为抽象方法。
- 抽象类:包含抽象方法的类就是抽象类。
- 抽象就是从多个事物中将共性的,本质的内容抽取出来。
- 抽象类的特点
- 抽象类和抽象方法必须用abstract关键字来修饰。
- 抽象类不可以被实例化,也就是不可以用new创建对象。因为调用抽象方法没有意义。
- 抽象类中的方法要被使用,必须由其子类覆写所有的抽象方法后,建立子类对象调用。
如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
- 抽象类可以强制子类实现方法。
- 抽象类中可以不定义抽象方法,这样做仅仅是为了不让该类建立对象。
- 抽象类和抽象方法必须用abstract关键字来修饰。
- 模板设计模式(template pattern)
- 描述:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去,由该类的子类去完成。
- 实现:
- 定义一个抽象的父类做为模板,定义所有需要的方法。
- 在父类中实现供外界调用的主方法,将方法声明为final。
- 根据不同业务需求定义子类实现父类的抽象方法。
- 定义一个抽象的父类做为模板,定义所有需要的方法。
- 举例:
- 需求:获取一段程序的运行时间。
- 原理:获取程序开始和结束的时间并相减即可。
- 代码:
打印结果:package cn.itcast.heima; class GetTime { public void getTime(){ long start = System.currentTimeMillis();//开始时间 runcode(); long end= System.currentTimeMillis();//结束时间 System.out.println("运行时间:" + (end - start) + "毫秒"); } //要运行的程序 public void runcode(){ for (int i = 0; i < 10000; i++) { System.out.print(""); } } } class TemplateDemo{ public static void main(String[] args){ GetTime gt = new GetTime(); gt.getTime(); } }
由于每次要运行的程序是不确定的,因此应该把这部分代码定义为抽象的,由具体的子类根据实际需求实现该方法。从而使得父类成为一个统计程序运行时间的模板,而具体要统计什么程序的运行时间交给子类决定。
优化后的代码:
打印结果:package cn.itcast.heima; abstract class GetTime { public final void getTime(){ long start = System.currentTimeMillis();//开始时间 runcode(); long end= System.currentTimeMillis();//结束时间 System.out.println("运行时间:" + (end - start) + "毫秒"); } public abstract void runcode();//将要运行的程序定义为抽象方法 } class SubTime extends GetTime{ //实现父类的抽象方法,确定具体要运行的程序代码 public void runcode(){ for (int i = 0; i < 10000; i++) { System.out.print(""); } } } class TemplateDemo{ public static void main(String[] args){ GetTime gt = new SubTime();//定义子类对象 gt.getTime(); } }
- 接口
- 接口概述
- 接口是一种特殊的抽象类,接口中声明的所有方法都是抽象的。
- 格式:
interface {}
- 接口中的成员修饰符是固定的。
- 成员常量:public static final
- 成员函数:public abstract
- 成员常量:public static final
- 接口不可以创建对象,因为有抽象方法。只有子类实现该接口,且对接口中的方法全部覆盖后,子类才可以实例化。否则子类是一个抽象类。
- 接口经过编译也生成类文件。允许使用接口名.成员变量的方法访问成员变量。
- 接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。
- 接口之间支持“多继承”,但是接口之间的多继承不允许出现返回类型不同的同名函数,否则编译失败。
- 接口是一种特殊的抽象类,接口中声明的所有方法都是抽象的。
- 接口的特点
- 接口是对外暴露的规则。
- 接口是程序的功能扩展。
- 接口可以用来多实现。
- 类与接口之间是实现关系,而且类可以 继承一个类的同时实现多个接口。
- 接口与接口之间可以有继承关系。
- 接口是对外暴露的规则。
- 多态
- 多态概述
- 多态就是某一类事物的多种存在形态。
- 例如:
动物中猫,狗。
猫这个对象对应的类型是猫类型。
猫x = new 猫();
同时猫也是动物中的一种,也可以把猫称为 动物。
动物y = new 猫();
动物是猫和狗具体事物中抽取出来的父类型。
父类型引用指向了子类对象。
- 多态的体现:
- 父类或者接口的引用指向或者接收自己的子类对象。
- 父类或者接口的引用指向或者接收自己的子类对象。
- 多态的前提:
- 需要存在继承或者实现关系。
- 要有覆盖操作。
- 需要存在继承或者实现关系。
- 多态的好处:
- 多态的存在提高了程序的扩展性和后期可维护性。
- 多态的存在提高了程序的扩展性和后期可维护性。
- 多态的弊端:
- 只能使用父类的引用访问父类中的成员。
- 只能使用父类的引用访问父类中的成员。
- 多态就是某一类事物的多种存在形态。
- 多态的转型
- Animal a = new Cat();//类型提升。类的向上转型。
Cat c = (Cat)a;//如果想要调用猫的特有方法时,需要强制将父类的引用转成子类类型。类的向下转型。 - 父类的引用可以强转成子类类型,父类的对象不可以强转成子类类型。
- Animal a = new Cat();//类型提升。类的向上转型。
- 多态的特点
- 非静态成员函数:
- 编译时:要查看引用变量所属的类中是否有所调用的方法。
- 在运行时:要查看对象所属的类中是否有所调用的方法。
- 总结:成员函数在多态调用时,编译看左边,运行看右边。
- 编译时:要查看引用变量所属的类中是否有所调用的方法。
- 静态成员函数:
- 无论编译和运行,都参考左边。
- 成员变量:
- 无论编译和运行,都参考左边(引用变量所属的类)。
- 类的一个成员若想表现多态必须可以被覆盖:
- 对于成员变量而言,不会发生覆盖现象(会隐藏),在子类出现相同变量的定义时只会隐藏父类变量,因此不会表现多态。同时变量调用在编译时就会解析,不符合动态绑定的特征。
- 在成员方法中,静态方法和final方法(private方法)也不会发生覆盖现象(会隐藏),因此也不会表现多态性。
- 对于成员变量而言,不会发生覆盖现象(会隐藏),在子类出现相同变量的定义时只会隐藏父类变量,因此不会表现多态。同时变量调用在编译时就会解析,不符合动态绑定的特征。
- 动态绑定和静态绑定:
- 静态绑定:在程序执行前方法已经被绑定,此时由编译器或其它连接程序实现。简单的可以理解为程序编译期的绑定;java当中的方法只有final,static,private和构造方法是前期绑定。
- 动态绑定:在运行时根据具体对象的类型进行绑定。
- 非静态成员函数:
- Object类
- 概述
- Object类是所有对象的直接或者间接父类。
- 该类中该定义的是所有对象都具备的功能。
- equals方法
- Object类中已经提供了对象是否相同的比较方法。
- 如果自定义类中也要比较相同的同能,只要覆盖Object中的equals方法,建立自己特有的比较内容即可。
- toString方法
- toString()方法返回的是对象的字符串表示。
- 所有的类都可以覆盖Object类的toString()方法实现自己的显示功能。
- toString()方法返回的是对象的字符串表示。
- 内部类
- 定义
- 将一个类定义在另一个类的里面,对里面那个 类就称为内部类(内置类,嵌套类)。
- 将一个类定义在另一个类的里面,对里面那个 类就称为内部类(内置类,嵌套类)。
- 访问特点
- 内部类可以直接访问外部类中的成员,包括私有成员。
之所以可以直接访问外部类中的成员,是因为内部类中持有一个对外部类的引用,格式为:外部类名.this - 外部类要访问内部类中的成员必须要建立内部类的对象。
- 其它外部类直接访问非私有内部类成员的方法:
- 外部类名.内部类名 变量名 = 外部类对象.内部类对象
- 外部类名.内部类名 变量名 = 外部类对象.内部类对象
- 当内部类在成员位置上时,就可以被成员修饰符修饰,比如:
private:将内部类在外部类中进行封装。
static:当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。 - 内部类访问外部类的成员变量:
外部类.this.变量名
- 内部类可以直接访问外部类中的成员,包括私有成员。
- 静态内部类
- 静态内部类不用创建外部类对象就可以直接创建对象:
- 外部类名.内部类名 变量名 = new 外部类名.内部类名();
- 在其它外部类中,如何直接访问static内部类的非静态成员:
- new 外部类名.内部类名().函数名();
- new 外部类名.内部类名().函数名();
- 在其它外部类中,如何直接访问static内部类的静态成员:
- 外部类名.内部类名().函数名();
- 外部类名.内部类名().函数名();
- 如果内部类定义了静态成员,该内部类必须是静态的。
- 如果外部类的静态方法访问内部类,该内部类必须是静态的。
- 静态内部类不用创建外部类对象就可以直接创建对象:
- 局部内部类
- 局部内部类也可以访问外部类的成员。
- 局部内部类不能用static修饰,static只修饰成员。
- 局部内部类里面不能定义静态方法。
- 如果内部类访问局部变量,该变量必须被final修饰。
- 局部内部类也可以访问外部类的成员。
- 匿名内部类
- 匿名内部类就是内部类的简化写法。如果一个类只使用一次,那么可以定义为匿名内部类。
- 定义匿名内部类的前提:
- 内部类必须继承或实现一个外部类或者接口。
- 内部类必须继承或实现一个外部类或者接口。
- 定义匿名内部类的格式:
- new 外部类名或者接口名(){
覆盖类或者接口中的代码, (也可以自定义内容。)
}
- new 外部类名或者接口名(){
- 匿名内部类就是一个匿名子类对象。
- 匿名内部类中定义的方法最好不要超过3个。
- 匿名内部类就是内部类的简化写法。如果一个类只使用一次,那么可以定义为匿名内部类。
- 异常
- 异常概述
- 异常就是Java程序在运行过程中出现的错误。如程序要打开一个不存的文件、网络连接中断、操作数组越界、装载一个不存在的类等。Java通过类的形式将其封装成对象。
- 异常的体系:
- Throwable
- Error:通常出现重大问题如,运行的类不存在或者内存溢出等。不编写针对代码对其处理。
- Exception:在运行时运行出现的一些情况,可以编写针对性的代码对其处理。
- Error:通常出现重大问题如,运行的类不存在或者内存溢出等。不编写针对代码对其处理。
- Throwable
- Exception和Error的子类名都是以父类名作为后缀。
- 异常的好处:
- 将问题进行封装。
- 将正常流程代码和问题处理代码相分离,方便于阅读。
- 异常就是Java程序在运行过程中出现的错误。如程序要打开一个不存的文件、网络连接中断、操作数组越界、装载一个不存在的类等。Java通过类的形式将其封装成对象。
- Throwable中的方法
- getMessage():获取异常信息,返回字符串。
- toString():获取异常类名和异常信息,返回字符串。
- printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
- printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。
- getMessage():获取异常信息,返回字符串。
- 异常的处理
- 使用try……catch语句进行捕获,finally可以结合try……catch使用,出现异常,finally里面的代码也会执行。
Finally代码块只有一种情况不会被执行。就是在之前执行了System.exit(0)。 - 在程序中可以在方法后面使用throws关键字声明向外抛出异常。声明该功能可能会出现问题。
- 使用try……catch语句进行捕获,finally可以结合try……catch使用,出现异常,finally里面的代码也会执行。
- 多异常处理
- 声明异常时,建议声明更为具体的异常,这样处理可以更具体。
- 声明几个异常,就对应几个catch块。
- 如果异常出现继承关系,父类异常catch块放在最下面。
- 建立进行catch处理时,catch中一定要定义具体的处理方式。不要简单地定义e.printStackTrace(),也不要简单地打印一条输出语句。
- 可以将异常内容保存在日志文件中。
- 可以将异常内容保存在日志文件中。
- 自定义异常
- 自定义类继承Exception或者其子类。
- 因为项目中会出现特有的问题,而这些问题并未被Java锁描述并封装成对象。
- 对应这些特有的问题,可以按照Java对问题封装的思想,将特有的问题进行自定义的异常封装。
- 可抛性是Throwable体系中独有的特点。只有这个体系中的类和对象才可以被throws和throw操作。
- 通过throw关键字手动抛出自定义异常对象
- 处理函数抛出的自定义异常:
- 要么在内部try-catch处理。
- 要么在函数上声明让调用者处理。
- 自定义类继承Exception或者其子类。
- throws和throw
- thorws用在函数上,后面跟异常类名,可以跟多个,用逗号隔开。
- throw用在函数内,后面跟异常对象。
- thorws用在函数上,后面跟异常类名,可以跟多个,用逗号隔开。
- RuntimeException
- 如果在函数内抛出该异常,函数上可以不用声明,编译可以通过。
- 如果在函数上声明了该异常,调用者可以不用进行处理,编译可以通过。
- 之所以不用再函数声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,需要对代码进行修正。
- 自定义异常时,如果该异常的发生,导致无法再继续进行运行,就让自定义异常继承RuntimeException。
- 除了RuntimeException的其它异常为编译时异常。
- finally
- finally中存放的是一定会被执行的代码。
- 通常关闭资源的动作都放在finally中。保证即使程序出现异常,也能正常关闭资源。
- 在分层设计时,异常要在层内封装。
- 出现异常时,要在本层内处理,并把本层无法解决的相关问题转换为其它异常,继续向上层抛出。
- 异常处理的三种格式:
- try-catch
- try-catch-finally
- try-finally
- try-catch
- 覆盖时的异常特点
- 如果父类方法抛出了异常,那么子类在覆盖父类方法时,只能抛出该异常或该异常的子类。
- 如果父类方法抛出了多个异常,那么子类在覆盖父类方法时,只能抛出父类异常的子集。
- 如果子类方法发生了父类没有的异常,就只能在方法内进行try-catch处理,不能抛出。
- 如果父类方法抛出了异常,那么子类在覆盖父类方法时,只能抛出该异常或该异常的子类。
- 包(package)
- 对类文件进行分类管理。
- 给类提供多层命名空间。
- 写在程序文件的第一行。
- 类名的全称的是 包名.类名。
- 包也是一种封装形式。
- 包与包之间访问,被访问的包中的类及类中的成员,必须被public修饰。
- 不同包中的子类可以访问父类中被protected修饰的成员。
- 类成员之间的四种访问权限:
- import:
- 简化类名。
- 一个程序文件中只有一个package,可以有多个import。
- 用来导包中的类,不导入包中的包。
- 简化类名。
- Jar包
- Java的压缩包
- 方便项目的携带。
- 方便于使用,只要在classpath设置jar路径即可。
- 数据库驱动,SSH框架等都是以jar包体现的。
- 方便项目的携带。
- 可以将类文件用jar命令压缩成jar包,并配置相应的classpath环境变量为jar包路径(包含jar包名)。
- 封装好的jar包放到classpath路径下就可以参考说明文档直接使用了,非常方便。
- DOS下的数据重定向命令:> 路径
- java的类库:jre下的lib\rt.jar
java的编译环境工具类:jdk下的lib\tools.jar
java的源文件:jdk下的src.zip
- 通过jar.exe工具对jar的操作:
- 创建jar包:
jar -cvf mypack.jar packa packb
- 查看jar包:
jar -tvf mypack.jar [>定向文件]
- 解压缩:
jar -xvf mypack.jar
- 自定义jar包的清单文件:
jar –cvfm mypack.jar mf.txt packa packb
- 创建jar包:
- jar命令:
- 用法: jar {ctxui}[vfm0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
选项包括:
-c 创建新的归档文件
-t 列出归档目录
-x 从档案中提取指定的 (或所有) 文件
-u 更新现有的归档文件
-v 在标准输出中生成详细输出
-f 指定归档文件名
-m 包含指定清单文件中的清单信息
-e 为捆绑到可执行 jar 文件的独立应用程序指定应用程序入口点
-0 仅存储; 不使用情况任何 ZIP 压缩
-M 不创建条目的清单文件
-i 为指定的 jar 文件生成索引信息
-C 更改为指定的目录并包含其中的文件 - 如果有任何目录文件, 则对其进行递归处理。
- 清单文件名, 归档文件名和入口点名称的指定顺序与 'm', 'f' 和 'e' 标记的指定顺序相同。
- 示例 1: 将两个类文件归档到一个名为 classes.jar 的归档文件中:
- jar cvf classes.jar Foo.class Bar.class
- 示例 2: 使用现有的清单文件 'mymanifest' 并将 foo/ 目录中的所有文件归档到 'classes.jar' 中:
- jar cvfm classes.jar mymanifest -C foo/。
- 用法: jar {ctxui}[vfm0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
- Java的压缩包