0%

java面向对象

JAVA面向对象

第一章 抽象和封装

一、面向对象

1、类(Class)和对象(Object)

万物皆对象。

类:具有相同特征(属性)与行为(方法)的对象我们可以把它归纳为一个类别,这个类别就是类。

类和对象的关系:类是对象的模板,对象是类别的一个实例。(在Java中类就是数据类型,对象就是类的变量)

2、面向对象设计

面向对象设计的过程就是抽象的过程。分为以下三步来完成。

第一步:发现类

第二步:发现类的属性

第三步:发现类的方法

二、类图

类图用UML(统一建模语言),Power Designer软件进行画图

Dog
属性 +name:String
属性由修饰符 属性名和属性值的数据类型构成 +health:int
修饰符:+代表public ; -代表private ; #代表protected +love:int
属性 +strain:String
方法:由修饰符 方法名 参数:名字:类型,名字类型 和返回值构成 +print():void

注意:抽象时遵循的原则如下:

1、属性、方法的设置是为了解决业务问题

2、关注主要属性、方法

3、如没有必要,不用增加额外的类、属性与方法

三、构造方法和方法重载

1、构造方法(Constructor)

Java 可以通过无参或带参数的构造方法可以完成赋值的初始化工作。构造方法是一个特殊的方法,没有构造方法时,系统会提供一个空的构造方法。你在new一个对象的时候就是在调用这个方法。请注意:当你自己定义构造方法时,系统不再生成无参的构造方法。

一个类可以提供多个构造函数,但是要求,参数列表必须不一样。

语法:

​ 修饰符 类名( ){

​ //初始化代码

​ }

//快捷键生成构造方法 alt + shift + s + o

2、构造方法的作用和特点

特点:构造方法的名称和类名相同,没有返回值类型。

作用:在创建对象时,执行一些初始化操作,如给成员属性赋初始值

建议:生成有参构造函数后,再生成一个无参构造函数

3、构造方法的重载(Overload)

在同一个作用域中(类),方法名相同,参数列表不同(方法的参数类型、个数、顺序至少有一个不同,和参数类型定义的属性名称没有关系),就是方法重载。

方法重载与 访问修饰符 和 返回值类型无关。

4、构造方法的作用域

1、当前类的其他构造方法通过this语句调用它

2、当前类的子类的构造方法通过super语句调用它

3、在程序中通过new语句调用它

四、static关键字

作用:能被类的所有实例共享,可作为实例之间进行交流的共享数据;如果类的所有实例都包含一个相同的常量属性,可把这个属性定义为静态常量从而节省内存空间。

孙卫琴:p223-230

static可以用于修饰 属性、方法、代码块。在加载类的过程中,完成静态变量的内存分配,再执行静态块,两者是在创建之前执行的。注意:在加载类的时候,static修饰的属性、方法、代码块只会初始化一次。

1、static 修饰的变量属于这个类所有,即由这个类所创建的所有对象共用同一个static变量。即在类的内部,可以 在任何方法内直接访问它的静态变量

2、static(静态的)声明的属性,称之为 静态变量; 没有使用static声明的就是实例变量。

静态变量和实例变量的区别是:①实例变量必须使用 对象调用 ,而类变量可以使用类名直接调用。

​ ②、静态变量在内存中只存在一个拷贝,只为它分配一次内存;实例变量每创建一 个实例,就分配一次内存

3、static修饰的方法,叫做静态方法。

在静态方法中,不能使用普通的成员(实例)变量。

在静态方法中,不能使用this和super关键字。

在静态方法中,只能访问类属性和其他类方法。

静态方法不能被重写

4、在普通方法中不能使用静态变量,即静态变量不能是局部变量。且局部变量必须要有初始值

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
26
27
28
29
30
31
public class Dog {
private String name = "旺财"; // 昵称
private int health = 100; // 健康值
private int love; // 亲密度
String sex; //公 母
static String MALE = "公";
static String female = "母";

//static修饰的方法,叫做静态(类)方法
public static void bite() {
//在静态方法中,也不能使用普通的成员(实例)变量
sex = "公";
System.out.println("我要咬你");
}

static int num;

//static修饰代码块
static {
num = 100;
System.out.println(num);
}

public void play(int n) {
int localv = 0; //局部变量,必须要有初始值。

//在普通方法中,不能使用静态变量;
// static int i = 0;
health = health - n;
System.out.println(name + " " + localv + " " + health + " " + love);
}

五、封装

1、封装的好处:隐藏类的实现细节,让使用者只能通过程序规定的方法来访问数据,程序员可以方便地加入存取 控制语句,限制不合理操作(提高类的安全性和合理性)

2、封装的步骤:

​ 第一步:修改属性的可见性来限制对属性的访问,使用权限控制符控制属性或方法的可见性

​ 第二步:为每个属性创建一对赋值(setter)方法和取值(getter)方法,用于对这些属性的存取

​ 第三步:在赋值方法(setter)中,加入对属性的存取控制语句,避免出现不合理需求赋值

3、权限控制符

①pirivate(私有的):成员变量和方法只能在其定义的类中被访问,如果要在外部访问,就需要使用setter和 getter方法访问。

②friendly(默认,不写):只能在同一个包里访问

③protected(受保护的):可以被同一个包中的类访问,被同一个项目中不同包的子类访问

④public(公共的):可以被同一个项目中所有类访问,具有项目可见性,是最大的访问权限

六、this关键字

this是对当前对象的一个默认引用,用于区分同名成员变量。在实例方法内部,都有一个this引用变量,指向调用这个方法的对象。

1、this只能调用实例变量、实例方法和构造方法

2、this不能调用类变量和类方法,也不能调用局部变量。

【回顾:1、成员变量(也就是在类中声明的变量:它在整个类中有效)

​ 2、局部变量(在方法内声明的变量就是局部变量,包括方法的参数也是属于局部变量,局部变

​ 量只能在当前的方法中有效。)】

七、笔记

1、一般属性不会给值(成员变量),除非值是固定的,成员变量的值,必须要new了个对象才能使用

2、常见错误:

1、方法内部定义的变量(局部变量)必须赋初始值、

2、在普通方法中不能使用静态变量static修饰的变量

3、在静态方法中也不能使用普通变量

第二章 继承

继承可以提供代码的可重用性,可维护性,可扩展性。但是继承会增加代码的耦合度。

一、继承(inheritance)

相同属性和方法从父类继承,避免了代码重复,也方便了日后的代码修改。

1、语法

​ 修饰符 SubClass extends Superclass{

​ //类定义部分

​ }

解释:继承通过extends关键字实现,SubClass成称为子类或派生类(class 类名),Superclass称为父类或者基类、超类。

如果类前面的修饰符是public则该类在整个项目中可见,如果没有public修饰符,则该类在当前包可见。注意:不可以使用private和protected修饰类。

2、子类可以继承父类的哪些东西

首先:无法继承父类的构造方法,但是可以通过super关键字调用构造方法

分两种情况:

1、当Sub类和Super类位于同一个包中:Sub类继承Super类中public、protected和默认访问级别的成员变量和成员方法(即父类定义的属性和方法)。

2、当Sub类和Super类位于不同包中:Sub类继承Super类中public、protected访问级别的成员变量和成员方法(即父类定义的属性和方法)。

注意:从中可以看出无法继承private修饰的属性和方法。

访问修饰符 本类 同包 子类 其他
private
默认(friendly)
protected
public

3、继承的特性

Java中只支持单继承,即一个类只能 直接继承一个类。它们之间的关系是is a的关系。

尽管一个类只能有一个直接父类,但是它可以有多个间接的父类。如base1 extends base2 , sub extends base1

sub类间接继承了base2。

注意:所有的JAVA类都直接或者间接的继承了java.lang.Object类。Objiec类是所有Java类的祖先。

二、子类重新父类方法(@Override)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
* 方法重写: 方法名、返回值类型、参数列表、访问修饰符必须一致;
* 条件:
* 1.方法签名一致;(方法名、返回值类型、参数列表)
* 2.访问修饰符必须大于等于重写方法的访问权限
如父类修饰符是protected,那么子类方法重写的修饰符不能是默认或private
* 3.重写只存在继承关系
* 4.重写的方法不能抛出比被重写方法更多的异常
*
* 5.父类的静态方法不能被子类覆盖为非静态方法。
* 6.子类可以定义与父类的静态方法同名的静态方法,以便在子类中隐藏父类的静态方法。
* 7.父类的非静态方法不能被子类覆盖为静态方法;
* 8.父类的私有方法不能被子类覆盖;
* 9.父类的抽象方法可以被子类通过两种途径覆盖:一是子类实现父类的抽象方法;二是子类重新声明父类的抽象方法;
* 10.父类的非抽象方法可以被覆盖为抽象方法。

三、继承关系的构造方法,super关键字

1、super关键字介绍

super关键字是一个指示编译器调用超类方法的特殊关键字。

1、super必须出现在子类(子类的方法和构造方法)中,而不是其他位置

2、super可以访问父类的成员,如父类的属性、方法、构造方法

3、注意访问权限的限制,如无法通过super访问private成员

2、继承关系中的构造方法

①用super关键字来调用父类的构造方法时,需要遵循的原则:

1、在子类构造方法中,不能直接用父类方法名调用父类构造方法,而是用super语句

2、如果在子类的构造方法中有super语句,它必须作为构造方法的第一条语句。

②在创建子类的对象时,JAVA虚拟机首先执行父类的构造方法,然后再执行子类的构造方法,在多级继承的情况下,将从继承数的最上层父类开始,依次执行各个类的构造方法,这样可以保证子类对象从所有直接或间接父类中继承的实例变量都被正确的初始化。

③子类的构造方法中没有通过super显示调用父类的有参构造方法,也没有通过this显示调用自身的其他构造方法,则系统会默认先调用父类的无参构造方法,写不写super()都一样。

1
2
3
super.name;	//访问直接父类的name属性
super.print(); //访问直接父类print方法
super(name);//访问直接父类对应的构造方法,只能出现在构造方法中

四、抽象类(abstract)

abstract不能修饰属性和构造方法,可以修饰类和方法。抽象类是为了某些没有意义的类进行实例化而延伸出的概念。

抽象类和抽象方法的特点:

1、抽象类和抽象方法都通过abstract关键字来修饰

2、抽象类不能被实例化。抽象类不一定有抽象方法。

3、抽象方法只有方法声明,没有方法实现,即没有方法体。有抽象方法的类必须声明为抽象类。子类必须重写所有的抽象方法才能实例化,否则子类还是一个抽象类。(如果子类也是个抽象类,抽象方法可以不重写)、

4、抽象类可以有构造方法,其构造方法可以被本类的其他构造放调用,若此构造方法不是有private修饰,也可以被本类的子类中的构造方法调用。

5、abstract不能和private/static同时修饰一个方法,abstract 不能和final修饰一个方法或类。

五、final修饰符

1、用final修饰的类,不能再被继承,没有子类。

2、final修饰的方法可以被继承但是不允许被子类方法覆盖。所以final和abstract不能连用。

3、final修饰的变量表示常量,只能被赋值一次

4、final不能被用来修饰构造方法

5、局部变量只有final可以修饰,不可以用其他修饰符修饰

孙卫琴:p217-222

第三章 多态

p189

一、多态

1、什么是多态

在JAVA中,同一个引用类型(同一个实现接口),使用不同的实例而执行不同的操作

2、为什么使用多态

通过多态可以减少类中的代码量,可以提高代码的可扩展性和可维护性。继承是多态的基础,没有继承就没有多态

3、实现多态的3个条件

①继承的存在

②子类重写父类方法

③父类引用变量指向子类对象

二、父类引用变量和子类实例间的类型转换

1、向上转型(upcasting)

将一个父类的引用指向一个子类对象,属于自动进行转换。此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,不能调用子类特有方法

1
2
3
4
5
6
7
8
9
10
11
12
13

public static void main(String[] args) {
Master master = new Master();

//父类的引用 指向 子类的对象,会自动进行类型转化,称之为向上转型
Pet pet = new Dog();
Pet pet1 = new Cat();
Pet pet2 = new Duck();

master.feed(pet);
master.feed(pet1);
master.feed(pet2);
}

2、向下转型

将一个指向子类对象的父类引用赋给子类的一个引用,此时必须进行强制类型转换。转换后可以调用子类特有方法。

1
2
3
4
5
6
7

public static void main(String[] args) {
Master master = new Master();
Pet pet = new Dog();
Dog dog =(Dog)pet; //向下转型,进行强制转换
Cat c =(Cat)pet;//这个将会报错,因为pet是父类的引用,实例是狗,但是现在讲狗强行转换成猫
报错词条为:ClassCastException

三、instanceof 运算符

为了避免出现ClassCastException异常,JAVA提供了instanceof运算符来进行类型的判断

1、语法

​ 对象 instanceof 类或接口

instanceof用来判断一个对象是否属于一个类或者实现了一个接口,结果为true或false。在强制转换之前通过instanceof检查对象的真实类型,对象的类型必须和instanceof的第二个参数所指定的类或接口在继承树上有上下级关系,否则会出现编译错误。

2、例子

1
2
3
4
5
6
7
8
9
10
11
12
public void bigMove(Hero hero) {
if(hero instanceof XiaoQiao) {
XiaoQiao xiaoqiao = (XiaoQiao)hero;
xiaoqiao.dazzlingStar();
}else if(hero instanceof DaJi) {
DaJi daji = (DaJi)hero;
daji.queenWorship();
}else if(hero instanceof ZhuGeliang) {
ZhuGeliang zgl = (ZhuGeliang)hero;
zgl.GasBomb();
}
}

四、多态的两种使用场景

1、使用父类作为形参

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
26
27
28
29
30
31
32
public abstract class Hero { //父类
private String name;
private int MP;
private int hurt;

public abstract int attack();

public class DaJi extends Hero { //继承了Hero父类
@Override //子类重写父类方法
public int attack() {
System.out.println("我是妲己,我的攻击力是"+setHurt(15)+"魔法"+super.setMP(super.getMP()-30));
return setHurt(15);
}

public class XiaoQiao extends Hero {
@Override
public int attack() {
System.out.println("我是小乔,我的攻击力是"+super.setHurt(10)+"魔法"+super.setMP(super.getMP()-20));
return setHurt(10);
}

public class Player {
public int player(Hero hero) { //使用父类作为形参,这样选择了哪个英雄就调用它重写的攻击方法
return hero.attack(); //如果不这么写,将每个子类的方法都写在上面,违反了开闭原则 //开闭原则: 对扩展开发,对修改关闭!
}

public class TestHero {
public static void main(String[] args) {
Player play = new Player();
Hero hero = new XiaoQiao();
hero.setMP(100);
play.player(hero);//调用父类作为形参的方法,调用的是父类引用指向的实例的子类的重写方法

2、使用父类作为方法返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
	public Hero select(int heroId) {	//使用父类作为方法返回值
Hero hero = null;
if(heroId==1) {
hero=new XiaoQiao();
System.out.println("你选择了小乔");
}else if(heroId==2) {
hero = new DaJi();
System.out.println("你选择了妲己");
}else {
hero = new ZhuGeliang();
System.out.println("你选择了诸葛亮");
}
return hero;
}

public class TestHero {

public static void main(String[] args) {
Player play = new Player();
Scanner input = new Scanner(System.in);
System.out.println("请输入要出战的英雄:1、小乔 2、妲己 3、诸葛亮");
int heroId = input.nextInt();
Hero hero=play.select(heroId); //父类引用接收玩家调用的父类作为返回值类型的方法,
hero.attack(); //输出发结果为,返回的英雄子类的重写方法

第四章 接口

孙卫琴:p236-261

一、接口

1、接口的作用

提高系统之间松耦合的有力手段,提高了系统的可扩展性和可维护性。

2、JAVA中接口的意思

一是指系统对外提供的所有服务,在对象中表现为public类型的方法声明。

二是指用interface关键字定义的实实在在的接口,也称为接口类型,它用于明确的描述系统对外提高的所有服务,它能够更加清晰的把系统实现细节与接口分离。

3、语法

1
2
3
4
5
6
7
8
9
10
//创建一个接口,关键字interface
修饰符 interface 接口名 (extends 父接口1,父接口2...){
//常量定义
//方法定义
}

//实现接口,关键字implements
class 类名 (extends 父类名) imlements 接口1,接口2,...{
//类成员
}

二、接口的特性

1、接口的命名规范与类相同,一般以”able“为后缀,表示可以做…,接口的修饰符只能是public或默认的。

2、接口中的属性都会自动用public static final修饰,即接口中的属性都是全局静态常量。接口中的常量必须在定义时指定初始值

3、接口中所有方法都是抽象方法,接口中的方法都会自动用public abstract修饰,即接口中只有全局抽象方法

4、接口不能被实例化,接口中不能有构造方法。但是允许定义接口类型的引用变量,该引用变量实现了这个接口的类的实例。

5、接口必须通过类来实现它的抽象方法,类实现接口的关键字是implements。接口的实现类必须实现接口的全部方法,否则必须定义为抽象类。写抽象类实现接口不会报错。

6、一个接口不能实现另一个接口,但是可以接口之间可以通过extends实现继承关系,一个接口可以继承多个接口,即复合接口,但是接口不能继承类。

7、一个类只能有一个直接父类,但是可以通过implements实现多个接口。如果类继承了父类又实现了多个接口,extends关键字必须位于implements关键字之前

三、接口的具体表现

1、接口表示一种能力

一个类实现了某个接口,就表示这个类具备了某种能力。

2、接口表示一种约定

创建接口,在接口内定义后面的实现接口的类都具备的一个方法(约定),然后再创建实现接口的具体类,重写这个方法,返回不同的值,然后再创建一个都遵循这个约定的类,类的属性使用接口名作为数据类型,创建一个有参构造方法,并在方法里用接口类作为形参。在测试类,用接口作为引用,要使用哪个实现类就new哪个实现类,,创建一个遵循这个约定的类的实例,然后调用有参构造方法。

接口体现了约定和实现相分离的原则,通过面向接口编程,可以降低代码间的耦合性,提高代码的可扩展性和可维护性。面向接口编程就意味着:开发系统时,主体架构使用接口,接口构成系统的骨架,这样可以同更换实现接口的类来更换系统。

第五章 设计模式

一、设计模式

1、概念

是一套反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式与编程语言无关。

2、种类

①分布式编程模式

②用户界面模式

③数据型模式

④面向对象模式

3、作用与目的

优点:提高代码的可复用性、可扩展性、可维护性、灵活性。

作用:高内聚,低耦合。

二、设计模式七大原则

这个原则其实就是告诉我们用抽象构建框架,用实现扩展细节的注意事项:单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合;开闭原则是总纲,告诉我们要对外扩展开发,对修改关闭。

1、单一职责原则(SRP):应该有且仅有一个原因引起类的变更,即一个类只负责一项职责。

2、里氏替换原则(LSP):判断是否适合使用继承。如果父类出现的地方子类可以无损替换。即父类可以替换子类,但是对于程序不会有任何影响。子类可以扩展父类的功能,但不能改变父类原有的功能

3、依赖倒置原则(DIP):能用接口的地方尽量用接口

4、接口隔离原则(ISP):接口的单一职能原则,建立单一接口,接口尽量细化,同时接口中的方法尽量少。

5、迪米特法则(Law of Demeter):最少知道原则,低耦合,(只和朋友交流,朋友的朋友和你无关(不要让第三个类);也要和朋友保持距离(方法不要完全暴露,用非public修饰符修饰方法))

6、开闭原则(OCP):对扩展开放,对修改关闭。尽量不要去修改源码。相当于上面5个人原则的总结。

7、组合/聚合复用原则(CARP):尽量使用合成/聚合,尽量不要使用类继承。

聚合:弱的拥有,

三、简单工厂模式(Simple Factory)

1、它的组成:

​ 1、工厂类角色(最后创建使用判断逻辑或商业逻辑去创建一个子类的实例的一个类,类里面含有一个父 类作为返回值的带参方法)

​ 2、抽象产品角色(先创建抽象父类)

​ 3、具体产品角色(再创建继承父类的子类)

2、缺点:违反了开闭原则,违反了高内聚分配原则

​ 优点:松耦合

四、工厂方法模式(Factory Method)

它的组成:

​ 1、抽象工厂角色(3创建一个含有创建产品角色的抽象方法)

​ 2、具体工厂角色(4最后依次创建生产产品角色的工厂,含有new产品角色的方法)

​ 3、抽象产品角色(1先创建抽象父类)

​ 4、具体产品角色(2再创建继承父类的子类)

测试类:先创建有抽象共产角色引用指向的一个工厂角色实例,然后再用抽象产品角色指向工厂角色实例调用的创建产品角色的方法,然后再用抽象产品角色的角色名调用具体产品角色负责的职责。

五、单例模式

一个类只有一个实例

两种形式:

1、饿(饥)汉式

单例类需要先在属性那里创建一个由静态和私有修饰符修饰的自我实例;然后将构造函数私有化,最后提供一个静态的公共的获取实例的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.hc.singleton;

/**
* 单例模式:一个类只有一个实例
* @author 24541
* 单例模式有两种形式:1.饿(饥)汉式
*/
public class Singleton {
//直接自己创建一个对象(实例)
private static Singleton singleton = new Singleton();


//单例类,需要将构造方法私有化
private Singleton() {
}

//提供静态的公共的获取实例的方法
public static Singleton getInstance() {
return singleton;
}

}

2、懒汉式

是一种懒加载的思想。在要用对象的时候再new对象

需要先在属性那里自我引用等于null,然后将构造函数私有化,最会提供一个静态同步的公共的获取实例的方法

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
26
27
package com.hc.singleton;

/**
* 单例模式:一个类只有一个实例
* @author 24541
* 单例模式有两种形式:2.懒汉式 。是一种懒加载的思想
*/
public class Singleton2 {
private static Singleton2 singleton = null;

private Singleton2() {
}


/**
* 获取实例
* 当高并发时,在判断时,可能出现对象多次创建的情况,造成一个类不止一个实例
* 怎么解决? 加锁。synchronized同步 加锁,
* @return
*/
public static synchronized Singleton2 getInstance() {
if(singleton == null) {
singleton = new Singleton2();
}
return singleton ;
}
}

第六章、项目总结

1、使用数组和静态变量来初始化各个级别需要用到的既定的,多个数据。数组的声明

2、String和StringBufffer的运用及其转换,连接字符串,和StringBuffer转换成String的语法,怎么创建StringBuffer实例。

String类用concat拼接,但是要用一个变量来接收拼接后的字符串:S=a.concat(“b”)

StringBuffer类用append在原有的字符串后追加字符串,不需要变量来接收

StringBuffer转换成String类,StringBuffer buffer = new StringBuffer()//创建StringBuffer实例; buffer.toString()//转换成String类;

3、随机数的声明:Random random = new Random();

4、System.currentTimeMillis();返回系统当前时间(以毫秒为单位),所以换算成秒,需要除以1000

5、System.exit(0);System.exit(1); // public static void exit(int status)终止当前运行的Java虚拟机。 该参数作为状态代码; 按照惯例,非零状态码表示异常终止。

6、Game game =new Game(this); //这里面的this代表对 public Game(Player play) { this.play=play;}用户创建的Player类对象的引用。

7、基本的for循环和if else的使用。

8、在一个类的方法里调用其他类的方法来实现这个类需要实现的这个方法。

第七章 程序异常与log4j

一、异常的概念(Exception)

p264-300

1、异常是由JAVA应用程序抛出和处理的非严重错误,它可以分为Checked异常和运行时异常两大类。异常是Throwable的子类,Throwable有2个直接子类,一个是Exception,一个是Error(靠程序本身无法恢复的严重错误)

2、Checked(受检)异常:异常类和任何不是RuntimeException的子类的子类都是检查异常(直接受到jvm检查的异常,程序必须处理该类异常,不然会编译错误)。必须捕获或者声明抛出,否则无法通过编译。处理方式包括两种:通过try-catch在当前位置捕获并处理异常;通过throw声明抛出异常,交给上一级调用方法处理。

3、运行时异常(RuntimeException)不要求必须捕获或者声明抛出,如果运行时发生异常,会输出异常的堆栈信息并中止程序运行(如:ArryIndexOutOfBoundsException、NullPointerException、InputMismatchException)

二、异常处理

1、常见的异常类型

异常 说明
Exception 异常层次结构的根类
ArithmeticException 算数错误情形,如以零作除数
ArryIndexOutOfBoundsException 数组下标越界
NullPointerException 尝试访问null对象成员
ClassNotFullException 不能加载所需的类
InputMismatchException 欲得到的数据类型与实际输入的类型不匹配
illegalArgumentException 方法接收到非法参数
ClassCastException 对象强制类型转换出错
NumberFormatException 数字格式转换异常,如把“abc“转换成数字

在Eclipce的报错里,先看报错类型,再找到自己写的那句代码报错行数查看。

2、Java异常处理通过5个关键字来实现

try、catch、finally、throw和throws

1、try{}:将可能出现异常的代码放在try块中进行监视。try块中的变量,不可以在catch和finally块中使用,除非写在try块外面。

2、catch(exception e){}: catch捕获异常,cacth块中可以将捕获的异常进行处理

3、finally{}:就是不管是否出现异常,始终会被执行的代码,比如必须关闭的资源。唯一不被执行的情况:在异常处理代码中执行System.exit(1),exit里是数字几,都将退出Java虚拟机。

4、throw:使用throw手动抛出的异常会被JAVA虚拟机接收,会在下面提示处理,相当于是一个提示。throw语句后面不可以跟其他语句,因为这些语句永远不会被执行

5、throws:用于声明异常,自身不做异常处理,而是交给调用者处理

3、对5个关键字的具体分析

1、try-catch捕获异常:首先执行try语句块中的语句,有三种情况

①try语句块正常执行完毕,不会发生异常,catch块中的所有语句都将被忽略

②try语句块在执行中遇到异常,这个异常与catch中声明的异常类型相匹配(完全一致或是其父类),那么在try语句块中剩余的代码将被忽略,而相应的Catch块将会被执行

③try语句块在执行中遇到异常,而抛出的异常在catch块里面没有被声明,那程序立刻退出

2、try-catch-finally:try块是必需的,catch和finally块至少出现其一。

分为两种情况

①try语句块正常执行完毕,那么finally块会被执行

②try语句块在执行中遇到异常,无论这种异常是否被catch都将执行finally块中的代码

③如果出现return语句,finally块也将被执行,如果出现异常:执行顺序为:try块或catch中return之前的语句,执行finally块中的语句,然后执行try块或catch中return语句退出。

3、try-catch-catch-catch-finally:分别捕获

多个catch的顺序必须是从子类到父类,最后一个一定是Exception类。

3、声明异常—throws,用于把异常抛出去给别人处理?

throws可以同时声明多个异常,用逗号隔开

两种方式:

一种:通过try-catch捕获并处理异常,调用者处理

另一种:通过throws继续声明异常(交给别人处理),如果调用者不打算处理该异常,可以通过throws声明异常,让上一级调用者处理异常(不太建议用这种)

4、抛出异常—throw,手动抛出,自己声明这个异常?你自己觉得这个地方有异常

注意:throw和throws的区别:

①作用不同:throw用于在程序中抛出异常;throws用于声明在该方法内抛出了异常

②使用位置不同:throw位于方法体内部,可以作为单独语句使用;throws必须跟在方法参数列表的后面,不能单独使用

③内容不同:throw抛出一个异常对象,而且只能是一个;throws后面跟异常类,而且可以跟多个异常类

5、访问异常信息

如果程序需要在catch块中访问异常对象的相关信息,可以通过调用catch后异常形参的方法来获取

所有异常对象都包含的几个常用方法

①getMessage():返回该异常的详细描述字符串。需要自己放在print里,且输出的是关键信息,不够详细

②printStackTrace():将该异常的跟踪栈信息输出到标准错误输出,自己会打印,且会精确到行,一般用这个。

③printStackTrace(PrintSteam s):将该异常的跟踪栈信息输出到指定输出流

④getStackTrace():返回该异常的跟踪栈信息

6、使用finally回收资源

为了保证一定能回收try块中打开的物理资源,异常处理机制提供了finally块。

finally中不要使用return或throw,因为这会使try,catch中的return或throws失效

三、自己定义的异常类

Exception类并没有定义它自己的任何方法,继承了Throwable类提供的方法,也可以自定义的异常类中覆盖这些方法中的一个或多个方法。

四、异常处理规则

1、不要过度使用异常,

2、不要使用过于庞大的try块

3、避免使用catch all语句

4、不要忽略捕获到的异常:方案:处理异常;重新抛出新异常;在合适的层处理异常

五、Log4j

开源日志记录工具Log4j:以文件形式记录异常信息,程序正常运行的关键步骤信息

1、日志及分类

①SQL日志:记录系统执行的SQL语句

②异常日志:记录系统运行中发生的异常事件

③业务日志:记录系统运行过程,如用户登录、操作记录

2、下载log4j的Jar文件

地址:http://logging.apache.org/log4j/1.2/download.html

3、log4j的构成

配置3个方面的内容:

①根目录Logger(级别和目的地):日志写出器,供程序员输出日志信息

②目的地Appender(控制台、文件等等):日志目的地,把格式化好的日志信息输出到指定的地方去

③输出样式Layout:日志格式化器,用来把程序员的Logging request 格式化成字符串

4、怎么使用log4j记录日志

①将log4j.jar包放到项目中,每新开一个项目就要将log4j.jar放到里面去,jar包放入项目中后,点击右键

Build Path然后再点击Add to Build Path

②创建log4j.properties文件:可以直接将已经写好的log4j.properties放到src路径下,一般一个项目或者公司共用一个log4j.properties。当然也可以自己写,点击项目名称右键然后点击New—File—输入配置文件名,文件名的后缀必须是log4j.properties

③编写log4j.properties文件,配置日志信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
##log4j.properties配置文件的作用:在导入第三方jar包(插件包)时,起到一个说明配置的作用。
##设置记录日志的根配置,包括日志的级别 和 追加器的名称
##日志的级别:调试 debug < 信息 info < 警告 warn < 错误 error < 致命 fatal off关闭 all所有
log4j.rootLogger=warn,stdout,logfile

##----------------------------------------------------------
##配置追加器的类型ConsoleAppender 是控制台追加器
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
##Target源,输出源System.out 和 System.err
log4j.appender.stdout.Target=System.out
##设置日志输出的布局 SimpleLayout简单布局
#log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n

##----------------------------------------------------------
##FileAppender 文件追加器
log4j.appender.logfile=org.apache.log4j.FileAppender
### file是,输出的日志文件地址。
log4j.appender.logfile.File=hc2003.log ##文件名是可以自己定义的
### PatternLayout是表达式布局
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
### ConversionPattern就是定义表达式的内容,%d代表时间,%l代表line,就是日志记录的行数,%F 记录日志的文件,%p 日志优先级 %m 日志的信息 %n 换行
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n

④在程序中使用log4j记录日志信息

需要在类后面,main方法前写

public static Logger logger =Logger.getLogger(类名.class);

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.hc.log;

import java.util.Scanner;

import org.apache.log4j.Logger;

public class LogDemo {

/**
* 使用log4j的步骤: 1)导包:将jar复制到项目中,将jar 加到构建路径中,add build path 2)编写配置文件
* log4j.properties 3)在需要记录日志的地方,创建日志对象即可使用
*
* @param args
*/
public static Logger logger = Logger.getLogger(LogDemo.class);

public static void main(String[] args) {
Scanner in = new Scanner(System.in);
try {
logger.info("程序开始了");
System.out.print("请输入被除数:");
int num1 = in.nextInt();
System.out.print("请输入除数:");
int num2 = in.nextInt();
System.out.println(String.format("%d / %d = %d",
num1, num2, num1/ num2));
}catch (Exception e) {
logger.debug("除法出错了~~debug");
logger.info("除法出错了~~info");
logger.warn("除法出错了~~warn");
logger.error("除法出错了~~error");
logger.fatal("除法出错了~~fatal");
e.printStackTrace();
}finally {
System.out.println("最后被执行的代码!!");
}
}

}

5、log4j配置文件

log4j.rootLogger=warn,stdout,logfile

1、定义输出级别和目的地

warn指的日志记录器(Logger)的输出级别。级别从高到低有:off>fatal>error>warn>info>debug>all

日志记录器只输出那些级别高于或等于它的信息。如:级别为debug,将输出fatal、error、warn、info、debug;级别为error将只输出fatal、error级别的日志信息

2、详细配置日志输出目的地 Appender

stdout,logfile指的是日志输出目的地的名字,名字可以自己命名,可以有多个目的地,常用的目的地有两种:

①ConsoleAppender:输出日志事件到控制台。通过Target属性配置输出到System.out或System.err,默认是out

②FileAppender:输出日志时间到一个文件,通过File属性配置文件的路径及名称。

3、然后针对每个Appender设置日志布局类型Layout

Appender必须使用一个与之相关联 布局类型Layout,用来制定它的输出样式。最常用的Layout有3种:

①HTMLLayout:格式化日志输出为HTML表格

②SimpleLayout:格式:”输出级别Level——,日志消息“

③PattemLayout:根据制定的转换模式格式化日志输出,需要配置layout.ConversionPattern属性,

4、最后如果是PattemLayout格式就自定义layout.ConversionPattern属性

配置参数含义如下:

%d:用来设置输出日志的日期和时间,默认格式为IS08601,也可以指定格式,比如%d{yyyy-MM-ddHH:mm:ss}

%m:用来输出代码中指定的消息

%n:换行

%1:输出日志时间的发生位置,包括类名、发生的线程,以及在代码中的行数。

%p:输出优先级

%F:用来输出文件名

%M:用来输出方法名

第八章 集合框架

一、集合框架

1、概念

Java集合框架是为了表示和操作集合而规定的一种统一的标准体系结构。是为完美完美提供了一套性能优良、使用方便的接口和类,它们都位于java.util包中。

2、内容

集合框架都包含三大块内容

①对外的接口:表示集合的抽象数据类型,如Collection、List、Set、Map、Iterator

Collection接口:储存一组不唯一(允许重复)、无序的对象

Set接口继承Collection接口:存储一组唯一(不允许重复)、无序的对象,实现类是HashSet,TreeSet

List接口继承Collection接口:存储一组不唯一(允许重复)、有序(以元素插入的次序来放置元素,不会重新排列)的对象,它们的实现类是ArryList,LinkedList

Map接口:存储一组成对的键—值对象,提供key(键)到value(值)的映射。Map中的key不要求有序,不允许重复。value同样不要求有序,但允许重复。它的实现类是HashMap,TreeMap

Iterator接口:是负责定义访问和遍历元素的接口。

②接口的实现:集合框架中接口的具体实现:ArrayList、HashMap、HashSet

③对集合运算的算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算方法。Java提供了进行集合操作的工具类Collections。

二、List接口

List:存储一组不唯一(允许重复)、有序(以元素插入的次序来放置元素,不会重新排列)的对象

1、ArryList(数组列表)集合类

一片连续的空间存储,遍历效率高。

ArryList常用方法:

方法名称 方法说明
boolean add(Object o) 在列表末尾顺序添加元素,起始索引位置从0开始
void add(int index,Object 0) 在指定的索引位置添加元素,原索引位置及其后面的元素依次后移。
int size() 返回列表中的元素个数
Object get(int index) 返回指定索引位置处的元素,取出的是Object类,使用前要强转
boolean contains(Object o) 判断列表中是否存在指定元素
boolean remove(Object 0) 从列表中删除元素
Object remove(int index) 从列表中删除指定位置元素,起始索引位置从0开始
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
26
27
28
29
30
31
public class ListDemo {

public static void main(String[] args) {
Hero lb = new Hero("刘备");
Hero zy = new Hero("赵云");
Hero dz = new Hero("董卓");

//创建集合对象
List heroList = new ArrayList();
heroList.add(lb); //使用add()向集合中添加元素
heroList.add(zy);

heroList.add(0, dz); //指定下标添加

heroList.remove(1); //删除指定下标的元素
heroList.remove(dz);

System.out.println("集合的大小"+heroList.size());//size()集合的大小

Hero zgl = new Hero("诸葛亮");
boolean flag1 = heroList.contains(dz); // 如果此列表包含指定元素,则返回 true
boolean flag2 = heroList.contains(zgl);

System.out.println("flag1:"+flag1);
System.out.println("flag2:"+flag2);

for(int i=0;i<heroList.size();i++) {
Hero hero = (Hero) heroList.get(i);
System.out.println("三国英雄:"+hero.getName());
}
}

2、LinkedList(链表)集合类

增删改效率高,遍历效率相对低,所以插入删除数据较频繁时,使用LinkedList。ArryList方法LinkedList也适用,因为是链表式存储所以有它特有的方法:addFirst(),addLast(),removeFirst(),removeLast().

LinkedList特殊方法

方法名称 说明
void addFirst(Object o) 在列表是首部添加元素
void addLast(Object o) 在列表是末尾添加元素
Object getFirst() 返回列表中的第一个元素
Object getLast() 返回列表中的最后一个元素
Object removeFirst() 删除并返回列表中的第一个元素
Object removeLast() 删除并返回列表中的最后一个元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//使用链表
Hero cc = new Hero("曹操");
Hero gj = new Hero("郭嘉");
Hero smy = new Hero("司马懿");

LinkedList heroList2 = new LinkedList(); //
heroList2.add(cc);

heroList2.addFirst(smy); //LinkedList特有的方法,向头尾进行添加元素
heroList2.addLast(gj);

heroList2.removeFirst();

System.out.println("----------------------------------");
for(int i=0;i<heroList2.size();i++) {
Hero hero = (Hero) heroList2.get(i);
System.out.println("三国英雄:"+hero.getName());
}

System.out.println("集合的是否为空:"+heroList2.isEmpty()); //isEmpty()判断集合是否为空,空则返回true
heroList2.clear(); //清除所有元素
System.out.println("集合的大小:"+heroList2.size());
System.out.println("集合的是否为空:"+heroList2.isEmpty());

三、Set接口

存储一组唯一(不允许重复)、无序的对象,实现类是HashSet,TreeSet

1、Hashset

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.hc.demo;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetDemo {

public static void main(String[] args) {
Pig ff = new Pig("菲菲");
Pig crq = new Pig("超人强");
Pig xdd = new Pig("小呆呆");

//创建set使用 hashSet实现类
Set<Pig> pigSet = new HashSet<Pig>();
pigSet.add(ff); //因为set是无序的,所以没有指定下标添加的方法
pigSet.add(crq);
pigSet.add(xdd);

pigSet.add(ff); //set是唯一,也就是不允许重复。所以添加相同元素时,无效

System.out.println(pigSet.size());

//针对无序的遍历方式一:使用增强for循环 -->foreach
/**
* for(Type1 param2: param3) { }
* Type1需要遍历集合内元素的类型
* param2就是每次取出来元素的别名
* param3 就是需要被遍历的集合对象
*/
for(Pig pig:pigSet) {
System.out.println(pig.getName());
}

System.out.println("-------------------");

//使用foreach遍历数组
int[] arr= {1,22,66,88};
for(int num:arr) {
System.out.println(num);
}

System.out.println("------使用迭代器-------------");
//针对无序的遍历方式二:使用迭代器
Iterator<Pig> it = pigSet.iterator(); //可以理解为,之前set无序,现在将无序的集合交给迭代器管理,内部进行了排列
while(it.hasNext()) { //当 迭代器中下一个元素有值
Pig pig = it.next(); //取出迭代器中的下一个值
System.out.println(pig.getName());
}

}

}

四、Map接口

存储一组成对的键—值对象,提供key(键)到value(值)的映射。Map中的key不要求有序,不允许重复。value同样不要求有序,但允许重复。

1、HashMap

Map的常用方法:

方法名称 说明
Object put(Object key,Object value) 以“键-值对”的方式存储
Object get(Object key) 根据键返回相关联的值,若不存在指定键,则返回null
Object remove(Object key) 删除指定的键映射的“键-值对”
int size() 返回元素个数
Set keySet() 返回键的集合
Collection values() 返回值的集合
boolean containsKey(Object key) 若存在指定的键映射的“键-值对”,则返回true
boolean isEmpty() 若不存在键-值映射关系,则返回true
void clear 从此映射中移除所有映射关系
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.hc.ch08;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class MapDemo {


//建立国家英文简称和中文全名间的键值映射
public static void main(String[] args) {
//map是以key-value(键值对)的形式保存数据的集合
//map的接口实现类有:HashMap,HashTable,TreeMap
//<String,Object> 指定map的泛型 第一个String是 key的类型,第二个Object是value的类型
Map<String,Object> map = new HashMap<String,Object>();

map.put("CN", "中国"); //存值 使用put()方法
map.put("US", "美国");
map.put("JP", "日本");

map.put("JP", "脚盆"); //key唯一,当存储相同key时,会覆盖

System.out.println(map.get("JP")); //取值使用 get()方法

//判断是否在map中有某个键使用containsKey()方法
boolean flag = map.containsKey("US");
System.out.println(flag);

System.out.println("-----使用foreach循环遍历map-----");
//遍历map
Set<String> keySet = map.keySet(); //先获取 所有的key ;keySet()就可以获取所以的key并以set集合返回
for(String key:keySet) {
System.out.print("key值为:"+key);
System.out.println("---对应key的值为:"+map.get(key));
}

map.remove("US"); //从map集合中删除元素时,只能根据键值删除,使用remove(key)
System.out.println("当前map的大小为:"+map.size());

System.out.println("-----使用迭代器进行遍历map-----");
Iterator<String> it = keySet.iterator(); //将key的set集合,交给迭代器管理
while(it.hasNext()) {
String key = it.next(); //从迭代器中取出下一个值,也就是key
System.out.print("key值为:"+key);
System.out.println("---对应key的值为:"+map.get(key));
}
}

}

五、Iterator迭代器

Collection接口的iterate()方法返回一个Iterator,然后通过Iterator接口的两个方法即可方便的实现遍历

方法:boolean hasNext():判断是否存在另一个可访问元素; Object next():返回要访问的下一个元素

1
2
3
4
5
6
7
System.out.println("-----使用迭代器进行遍历map-----");
Iterator<String> it = keySet.iterator(); //将key的set集合,交给迭代器管理
while(it.hasNext()) {
String key = it.next(); //从迭代器中取出下一个值,也就是key
System.out.print("key值为:"+key);
System.out.println("---对应key的值为:"+map.get(key));
}

六、泛型(Generic)集合

泛型解决了通过get(int index)方法取出集合中元素必须强制类型转换。

使用泛型集合在创建集合对象时指定集合中元素的类型,从集合中取出元素时无须进行类型强制转换,并且如果把非指定类型对象放入集合,会出现编译错误。

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
26
27
28
29
30
package com.hc.demo;

import java.util.ArrayList;
import java.util.List;

public class ListDemo2 {
public static void main(String[] args) {
Hero lb = new Hero("刘备");
Hero zy = new Hero("赵云");
Hero dz = new Hero("董卓");

Pig zzx = new Pig("猪猪侠");

// 创建集合对象
//<E>代表泛型。泛型就是广泛的类型,代表什么类型都可以 。可以将<E>限定为<Hero>,也就是你想限定集合的类型
//没有泛型 List herolist = new ArrayList();
List<Hero> heroList = new ArrayList<Hero>();
heroList.add(lb);
heroList.add(zy);
heroList.add(dz);

System.out.println(heroList.size());

for(int i=0;i<heroList.size();i++) {
Hero hero = heroList.get(i);
//没有泛型必须强转:Hero hero =(Hero) heroList.get(i);
System.out.println("三国英雄:"+hero.getName());
}
}
}

第九章 使用JDBC访问MySQL数据库

一、JDBC简介

1、概念

JDBC充当了Java程序与各种不同数据库之间的中介。JDBC是java数据库连接技术(Java DateBase Connectivity)的简称,由一组使用Java语言编写的类和接口组成,可以为多种关系数据库提供统一访问。在JAVA中我们只需要正确加载JDBC驱动,正确调用JDBC API就可以进行数据库访问了。

2、JDBC API

由Sun公司提供,提供了java应用程序与各种不同数据库交互的标准接口,如Connection(连接)接口,Statement接口、ResultSet(结果集接口)、PreparedStetement接口等。开发者使用这些JDBC接口进行各类数据库操作

3、JDBC DriverManager

负责管理各种不同JDBC驱动,位于JDK的java.sql包中

4、JDBC驱动

JDBC驱动由各个数据库厂商提供,负责连接各种不同的数据库,它们都实现了JDBC API中定义的各种接口。访问MySQL和Oracle需要不同的驱动。

二、JDBC工作步骤或模板

1、加载JDBC驱动

​ 代码:Class.forName(“JDBC 驱动类的名称”)

2、与数据库建立连接

​ 代码:Connectio con =DriverManager.getConnection(URL,数据库用户名,密码)

URL:例jdbc:mysql://localhost:3306/epet?characterEncoding=utf-8

由jdbc:连接的数据库名称://本机地址:断就名称/数据库名称,为了解决在java新增的数据到数据库出现乱码问题,使用?characterEncoding=utf-8,设置字符编码格式来解决。

3、发送SQL语句,并得到返回结果

​ 代码:statement stmt=con.createStatement();

​ ResultSet rs=stmt.executeQuery(“要执行的SQL语句”)

4、处理返回结果

主要是针对查询操作的结果集,通过循环取出结果集中每条记录并做相应处理

代码:while(rs.next()){

​ int id =rs.getlnt(“id”);

​ String name =re.getString(“name”);

​ System.out.println(id+”+name”);

​ }

5、释放资源

注意关闭顺序,要先关闭ResultSet结果集,再Statement,最后Connection。

​ 代码:rs.close();

​ stmt.close();

​ con.close();

如果不需要这三个对象,可以显示关闭它们,代码:public void close();

示例代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package oop_ch09_01;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCTest {

//新增
public static void main(String[] args) {
Connection con = null;
Statement stmt = null;
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.建立连接
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/oop_jbdc?characterEncoding=utf-8","root","root");

//3.发送sql,获取结果集
stmt = con.createStatement(); //使用连接对象获取命令对象
String sql = "insert into sheep values(null,'懒羊羊','母','14')";
int result = stmt.executeUpdate(sql); //执行命令时,会有返回;修改返回的是 数据库中表受的影响的行数
//4.处理结果集
if(result > 0) {
System.out.println("新增成功~");
}else {
System.out.println("新增失败~");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//5.关闭资源
try {
stmt.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}

}

}

}

常见错误:

1、JDBC驱动类的名称书写错误,出现ClassNotFoundException异常

2、数据库连接字符串,数据库用户名、密码书写错误,出现SQLException异常

3、数据库操作结束后,没有关闭数据库连接,导致仍然占有系统资源

4、关闭数据库连接语句没有放到finally语句块中,导致语句可能没有被执行

三、Connection接口

负责连接数据库并担任传送数据的任务。

两种常用的驱动方式

1、JDBC-ODBC桥连方式

通过JDBC-ODBC桥连方式可以访问所有ODBC可以访问的数据库,但是不能提供很好的性能,不适合实际系统应用

2、纯Java方式连接数据库

纯Java驱动方式由JDBC驱动直接访问数据库,驱动程序完全用Java语言编写,运行速度快,而且具备跨平台特点。

先下载数据库厂商提供的驱动程序jar包,并将jar包引入工程中,并查看相关帮助文档,获得驱动类的名称和数据库连接字符串,然后开始进行编程,与数据库建立连接

四、Statement接口和ResultSet接口

1、Statement接口

由Connection产生,负责执行SQL语句

①获取Connection对象,然后使用Connection对象创建Statement对象( stmt = con.createStatement();),然后使用Statement对象将SQL语句发送到数据库中

②Statement接口的基本数据库操作方法:

ResulSet executeQuery(Sting sql)*:可以执行SQL查询并获取Result对象。

int executrUpdate(Sting sql):可以执行插入、删除、更新的操作,返回值是执行该操作所影响的行数

boolean execute(Sting sql):可以执行任意SQL语句,若结果为ResultSet对象,则返回true,若为更新技术或者不存在任何结果,则返回false

2、ResultSet接口

负责保存和处理Statement执行后所产生的查询结果

①ResultSet接口常用方法

方法名称 说明
boolean next() 将光标从当前位置向下移动一行
boolean prevoius() 将光标从当前位置向上移动一行
void close() 关闭ResultSet对象
int getInt(int columnIndex) 以int的形式获取结果集当前行指定列号的值
int getInt(String columnLable) 以int的形式获取结果集当前行指定列名的值
float getFloat(float columnIndex) 以float的形式获取结果集当前行指定列号的值
float getFloat(String columnLable) 以float的形式获取结果集当前行指定列名的值
String getString(int columnIndex) 以String的形式获取结果集当前行指定列号的值
String getString(String columnLable) 以String的形式获取结果集当前行指定列名的值
int getRow() 得到光标当前所指引的行号
boolean absolute(int row) 光标移动到row指定的行

五、PreparedStatement接口

PreparedStatement接口:Statement的子接口,也由Connection产生,同样负责执行SQL语句,与Statement接口相比,具有高安全性、高性能、高可读性和高可维护性的优点。可以有效解决SQL注入问题

1、使用PreparedStatement操作数据库的步骤

①创建PreparedStatement对象

​ 代码:PreparedStatement pstmt = con.prepareStatement(“sql执行语句”);

1
2
String sql ="insert into dog (name,health,love,strain)values(?,?,?,?)"; //使用?作为占位符,避免SQL注入隐患
p=con.prepareStatement(sql);
②设置每个输入参数的值

SetXxx()方法,Xxxx是与该参数对应的数据类型。

1
2
3
4
p.setString(1, "美美");	//这里的1就是SQL语句里的第几个?,使用预编译命令对象的setXxx方法替换,第一个参数是QL语句里的第几个?,第二个参数是具体参数,这里的Xxx就是第二个参数的数据类型
p.setInt(2, 90);
p.setInt(3, 0);
p.setString(4, "酷酷的雪瑞纳");
③执行SQL语句

ResulSet executeQuery():可以执行SQL查询并获取Result对象。

int executrUpdate():可以执行插入、删除、更新的操作,返回值是执行该操作所影响的行数

boolean execute():可以执行任意SQL语句,若结果为ResultSet对象,则返回true,若为更新技术或者不存在任何结果,则返回false

虽然和statement执行方法相同,但是不需要SQL语句做参数,SQL语句已经在创建对象PreparedStatement时指定了。

代码:

1
2
pstmt=con.prepareStatment(sql);
rs=pstmt.executrQuery();

第十一章 数据库访问层

一、数据持久化

1、持久化

持久化是将程序中的数据在瞬时状态和持久状态间转换的机制。Jdbc就是一种持久化机制,将程序直接保存成文本文件或xml文件也是持久化机制的一种实现,常用的就是将数据保存到数据库中。持久化的主要操作为:读取、查找、保存、删除、修改。

2、DAO模式

DAO(Data Access Objects):数据存储对象,是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。

DAO的作用:隔离业务逻辑层和数据访问层。

3、DAO模式的组成

每个类放在不同的包里

DAO接口:把对数据库的所有操作定义成抽象方法,可以提供多种实现。里面用实现类作为形参

DAO实现类:针对不同数据库给出DAO接口定义方法的具体实现。根据不同的数据库建立不同的接口实现类,重写接口里的方法。

实体类:用于存放和传输对象数据,里面的属性与数据库表字段名相对应

数据库连接和关闭工具类:避免数据库连接和关闭代码的重复使用,方便修改。即JDBC里的加载驱动,连接,关闭资源专用类

二、分层开发

一般分为:表示层(用户界面UI)、业务逻辑层(biz/server)、数据库管理层(DAO模式)。写代码时从底层往上写

DAO模式就是分层开发思想的一种具体体现

1、优势

①每一层专注于自己功能的实现,便于提高质量。

②便于分工协作,从而提高效率

③便于代码复用

④便于程序开发

2、原则

①封装性原则:每个层次向外提供公开的统一接口,而隐藏内部的功能实现细节,其他层次不能也没有必要了解其内部细节

②顺序访问原则:下一层为上一层提供服务,而不使用上一层提供的服务

③业务逻辑层可以访问数据访问层的功能,而数据库访问层不能访问业务逻辑层功能

3、使用实体类传送数据

把相关信息使用实体类封装,在程序中把实体类最为方法的输入参数或返回结果,实现数据传递,非常方便。

1.实体类的特征:

①实体类的属性都用private修饰,方法用public修饰

②对实体类提供无参构造方法,根据业务需求提供相应的有参构造方法。实体类最好实现java.io.Serilalizable接口,支持序列化机制,可以将该对象转换成字节序列而保存在磁盘上或在网络上传输

③如果实体类实现了java.io.Serilalizable接口,则应该定义属性serialVersionUID解决不同版本之间的序列化问题。

第十三章、 File/IO流

一、File

1、文件

相关记录或放在一起的数据的集合。常见文件类型:扩展名为txt/doc/xls/jpg/java/class等文件

2、java.io包

在java中,提供了java.io包,里面提供了一些接口和类,对文件和目录属性的操作、对文件读写的操作。

3、File

File对象即可表示文件,也可表示目录,利用它可以对文件或目录进行基本操作,如:名称、最后修改日期、文件大小

①创建File对象的语法:
1
2
3
4
	File  file = new File(String pathName);	
//如: File file = new File("C:\\Users\\Lenovo\\Desktop\\11.sql");

// pathName是文件保存的路径,文件路径的分隔符必须写成\\
②File常见方法
方法名称 说明
boolean exists() 判断文件或目录是否存在
boolean isFile() 判断是否是文件
boolean isDirectory() 判断是否是目录
String getPath() 返回此对象表示的文件的相对路径名
String getAbsolutePath() 返回此对象表示的文件的绝对路径名
String getName() 返回此对象表示的文件或目录的名称
boolean delete() 删除此对象指定的文件或目录
boolean createNewFile() 创建名称的空文件,不创建文件夹
long length 返回文件的长度,单位为字节,若文件不存在,返回0L

③示例

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package oop_ch13_demo;

import java.io.*;

public class FileMethods {

public static void main(String[] args) {
FileMethods fm =new FileMethods();
File file =null;
file=new File("C:\\Users\\Lenovo\\Desktop\\11.sql");
fm.create(file);
//fm.showFileInfo(file);
//fm.delete(file);

}

public void create(File file) {
if (!file.exists()) {
try {
file.createNewFile();
System.out.println("文件已创建!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}

public void delete(File file) {
if (file.exists()) {
file.delete();
System.out.println("文件已删除!");
}
}

public void showFileInfo(File file) {
if (file.exists()) {
if (file.isFile()) {
System.out.println("名称:"+file.getName());
System.out.println("相对路径:"+file.getPath());
System.out.println("绝对路径:"+file.getAbsolutePath());
System.out.println("文件大小:"+file.length()+"字节");
}
if (file.isDirectory()) {
System.out.println("此文件是目录");
}
}else {
System.out.println("文件不存在!");
}
}
}

二、Java的流IO

1、流:是指一连串流动的字符,是以先进先出的方式发送和接收数据的通道。程序和数据源之间是通过流联系起来的。

2、流可以分为输入流和输出流,也可以分为字节流和字符流。(InputStream/OutputStram;Reader/Writer。它们都是抽象类,不能实例化。)

三、读取文件

一、使用字节流读取文件(FileInputStream类是InputStream的子类)

作用就是将JAVA程序外的文件中的数据输入到内存中

1、读取数据的常用方法
方法名称 说明
int read() 从输入流读取1个8位的字节,把它转换为0~255之间的整数(asike码)返回
int read(byte[] b) 将数据读取到字节数组中
int read(byte[] b,int off,int len) 从输入流中读取最多的len长度的字节,保存到字节数组b中,保存的位置从off开始
void close() 关闭输入流
int avaliable() 返回从该输入流中可以读取(或跳过)的字节数的估计值,而不会被下一次调用此输入流的方法阻塞
2、使用FileInputStream读取文本文件的步骤

①引入相关类(import java.io.IOException/import java.io.InputStream/import java.io.FileInputStream)

②创建一个文件输入流对象

​ File file = new File(“C:\test.txt”);

InputStream fi=new FileInputStream(file);

③利用文件输入流的方法读取文本文件的数据

fi.available(); //可读取的字节数

fi.read(); //读取文件的数据

④关闭文件输入流对象

fi.close();

示例:

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
26
27
28
29
30
31
32
33
34
35
36
package oop_ch13_demo;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

//字节输入流InputStream,读取文本文件,read()
public class FileInputStreamTest {

public static void main(String[] args) throws IOException {
FileInputStream fis =null;

try {
fis=new FileInputStream("C:\\Users\\Lenovo\\Desktop\\hello.txt");
int data;
System.out.println("可读取的字节数:"+fis.available());
while ((data=fis.read())!=-1) {
System.out.println((char)data+"");
}
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}

}
}

}

二、使用Reader读取文本文件

1、FileReader读文本文件
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
26
27
28
29
30
31
32
33
34
35
36
37
package oop_ch13_demo;

//字符输入流Reader类,FileReader是它的子类
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class FileReadTest {
public static void main(String[] args) {
Reader fr =null;
StringBuffer sbf=null;
try {
fr=new FileReader("C:\\Users\\Lenovo\\Desktop\\hello.txt");
char ch[] = new char[1024];
sbf=new StringBuffer();
int length=fr.read(ch);
while ((length!=-1)) {
sbf.append(ch);
length=fr.read();
System.out.println(sbf.append(ch));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
System.out.println("错误!");
e.printStackTrace();
}
}
}

}
}
2、BufferReader读文件

BufferReader有一个特有的方法:readline(),读取一行数据,返回字符串。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package oop_ch13_demo;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

//BUfferReader字符流输入类,可避免每次都从数据源读取数据进行字符编码转换
public class BufferReaderTest {
public static void main(String args[]) {
FileReader fr =null;
BufferedReader br =null;

try {
fr=new FileReader("C:\\Users\\Lenovo\\Desktop\\hello.txt"); //创建fileReader对象
br=new BufferedReader(fr); //创建BufferedReader对象
//读取一行数据,BufferReader类特有方法
String line =br.readLine();
while (line!=null) {
System.out.println(line);
line=br.readLine();
}

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
System.out.println("文件不存在!");
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (fr != null) {
fr.close();
}
} catch (IOException e) {

e.printStackTrace();
}
}
}
}

四、写文件

1、使用OutputStream写文件

①方法
方法名称 说明
void write(int c) 写入一个字节数据
void write(byte[] buf) 写入数组buf的所有字节
void writr(byte[] buf,int 0ff, int len) 将字节数据组从off的位置开始,长度为len的字节数据输出到输出流中
void close() 关闭输出流
②步骤

①引入相关类(import java.io.IOException/import java.io.OutputStream/import java.io.FileOnputStream)

②创建一个文件输出流对象

​ File file = new File(“C:\test.txt”);

OutputStream fos=new FileOutputStream(file);

③利用文件输出流的方法把数据写入文本文件中

String str=”好好学习”

byte[] words =str.getBytes();

fos.write(words,0,words.length)

④关闭文件输出流对象

fos.close();

示例:

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
26
27
28
29
30
31
32
package oop_ch13_demo;

//使用字节流读写文本文件
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class OutputStreamTest {

public static void main(String[] args) throws IOException {
FileOutputStream fos=null;
try {
String str ="好好学习 Java";
byte[] words=str.getBytes();
fos=new FileOutputStream("C:\\Users\\Lenovo\\Desktop\\hello.txt");
fos.write(words, 0, words.length);
System.out.println("hello 文件已更新!");
}catch(IOException obj) {
System.out.println("创建文件时出错!");
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}

}

2、使用Writer写文件

①方法:

方法名称 说明
write(String str) 将str字符串里包含的字符输出到指定的输出流中
write(String str,in off,int len) 将str字符串里从off位置开始长度为len的字符输出到输出流中
void close() 关闭输出流
void flush() 刷新输出流

②步骤

1、引入相关类

2、创建一个FileWriter对象

3、利用FileWriter类的方法写文本文件

4、相关流对象的清空和关闭

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
26
27
28
29
30
31
32
package oop_ch13_demo;
//字符流写文本文件,FileWriter类
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class FileWriterTest {

public static void main(String[] args) {
Writer fw =null;

try {
fw=new FileWriter("C:\\Users\\Lenovo\\Desktop\\hello.txt");
fw.write("我热爱我的团队!");
fw.flush();
} catch (IOException e) {
System.out.println("文件不存在!");
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}

}

2、使用BufferedWriter

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package oop_ch13_demo;
//字符流写文本文件,BufferedWriter类
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriterTest {

public static void main(String[] args) {
FileWriter fw =null;
BufferedWriter bw =null;
FileReader fr = null;
BufferedReader br =null;
try {
fw=new FileWriter("C:\\Users\\Lenovo\\Desktop\\hello.txt");
bw=new BufferedWriter(fw);
//写入信息
bw.write("大家好!");
bw.write("我正在学习BufferedWriter。");
bw.newLine(); //插入换行符
bw.write("请多多指教!");
bw.newLine();
bw.flush(); //刷新缓冲区
fw.close(); //关闭流

//读取文件内容
fr = new FileReader("C:\\Users\\Lenovo\\Desktop\\hello.txt");
br = new BufferedReader(fr);
String line = br.readLine();
while (line!=null) {
System.out.println(line);
line=br.readLine();
}
} catch (IOException e) {
System.out.println("文件不存在");
e.printStackTrace();
} finally {
try {
if (bw!= null) {
bw.close();
}
if (br!= null) {
br.close();
}
if (fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}

}

五、读写二进制文件(图片)

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package test;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class task4 {

public static void main(String[] args) {
DataInputStream dis =null;
DataOutputStream out =null;

try {
FileInputStream fis =new FileInputStream("C:\\myFile\\top.bmp");
dis=new DataInputStream(fis);
FileOutputStream fos = new FileOutputStream("D:\\myPicture.bmp");
out=new DataOutputStream(fos);

int num;
while ((num=dis.read())!=-1) {
out.write(num);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (dis != null) {
dis.close();
}
}catch (IOException e) {

e.printStackTrace();
}
}



}
}

第十四章、XML与XML解析

一、XML(可扩展的标记语言)

1、定义

被设计用来传输和存储数据。

①XML最基本、最主要的“功能”就是在文档中逐加标记,而标记的添加必须遵循一 定的规则。规则是标记必须成对出现

②所使用的标记都是非预定义的,即用户自己定义的,只要遵循XML的标记命名规则,可以在文档内添加任何标记

③对于自定义的标记,用户可以在文档内或外进行说明。XML对所使用的标记进行说明的部分称为DTD,即文档类型定义。DTD定义了用户使用的所有标记之间的逻辑关系和结构,一般这个有专门的,我们需要按这个规定来写。

④XML文档的标记只描述文档的内容(文档的结构和意义),不描述其如何显示、输出等格式化信息

2、XML的作用

①不同系统平台间的信息互通

②整合多种不同数据源的数据

③平衡客户端和服务端的处理负荷

④以灵活多变的方式显示数据

⑤更精确的数据检索

⑥更长的生命力、

二、解析XML

XML解析方式分为四种:

1、DOM解析(将XML文档转换成一个对象模型的集合,随机访问机制,但是一次性读取对内存消耗大,容易溢出)

2、SAX解析(顺序访问模式,速度快,内存消耗小,但编码麻烦,很难同时访问XML文件中的多处不同数据)

3、JDOM解析(仅使用工具类,不适用接口,使用了大量的Collections)

4、DOM4J解析:JDOM的智能分支,合并了许多超出基本XML文档表示的功能,它使用接口和抽象基本类方法

​ 性能优异、灵活性好、功能强大和极端易用,是一个开放源码的文件。所以了解这种即可

步骤:1、导入DOM4J的包,并且build path

​ 2、创建XML文件,可以直接放在JAVA项目下,新建,其他,选择XML类型文件建立,然后点击source输入 要写的内容

​ 3、建立一个类,开始解析:

​ ① 创建流对象,由Dom4j相关的jar提供SAXReader
​ SAXReader saxReader = new SAXReader();

​ ②将文件和 file对象关联
​ File file = new File(“NewFile2.xml”);

​ ③读取xml文件会 生成一个document文档对象(document类)

​ Document document = saxReader.read(file);

​ ④获取根节点元素(Element 类,通过实例可以调出其方法, root.getName()可以获取根节点元素名 称)

​ Element root = document.getRootElement();

​ ⑤通过根节点元素获取子节点元素(是Element 类的elements()方法,返回的是一个列表)

​ List elements = root.elements();

​ ⑥通过foreach遍历子节点元素,然后需要子节点下面的元素称为孙节点,可以先用是Element 类的 elements()方法获取孙节点,继续遍历,可以通过Element 类的getText()获取元素的文本

三、DOM4J解析代码示例

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.hc.xml;

import java.io.File;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
* dom4j解析xml
*
* @author 24541
*
*/
public class Dom4jParseXmlDemo {

@SuppressWarnings("unchecked")
public static void main(String[] args) {
try {
// 创建流对象,由Dom4j相关的jar提供
SAXReader saxReader = new SAXReader();
// 将文件和 file对象关联
File file = new File("book.xml");

//读取xml文件会 生成一个document文档对象
Document document = saxReader.read(file);
//获取根节点元素
Element root = document.getRootElement();
System.out.println(root.getName());

//通过根节点元素获取子节点元素
List<Element> elements = root.elements();
//遍历子节点
for (Element element : elements) {
System.out.println("---------------------");
//通过元素中 属性的键值,获取属性的值
System.out.println(element.attributeValue("id"));
//获取孙节点元素
List<Element> childElements = element.elements();
for (Element element2 : childElements) {
//获取元素的 文本
System.out.println(element2.getText());
}
}
} catch (DocumentException e) {
e.printStackTrace();
}

}
}

第十六章、反射

一、类对象

Java中有个类,java.lang.Class类。这个类的对象,被称之为类对象。

1、获取类对象

三种方法:

①类名.class

例如:要获取Student类的类对象,Class c =Student.class,基本类型只能用这个方法来获取类对象,如:Class c = int.class

②getClass()方法

Object类中定义了getClass()方法,即获得对象的实际类型,对象的类的比较用“==”,这个方法的作用:通过类的对象获得类对象

③Class.forName()方法

forName是Class类的一个静态方法,,可以根据类名返回类对象。它的签名是

public static Class forName(String className)throw ClasNotFoundException

如果className不存在就声明异常,如果有,className需要带包名。如Class.forName(“java.util.ArrayList”)

2、使用类对象获取类的信息

方法名称 说明
getName() 获得类的名称,包含包名
getSimpleName() 获得类的名称,不包括包名
getSuperClass() 获得本类的父类的类对象
getInterfaces() 获得本类所实现的所有接口的类对象,返回值类型为class[]

3、使用类对象获取类中方法的信息

① public Method[] getDeclaredMethods() throws SecurityException

返回的Method数组中,包括在本类中定义的所有方法,包括私有方法,但是不能获得父类中的任何方法

②public Method[] getMethods() throws SecurityException

返回的Method数组中,包括所有的公开方法,包括父类中定义的公开方法,但是私有方法不会被获取

注解:

SecurityException未检查异常,处理不处理皆可;

Method类是java.lang.reflect包中定义的类,可以用getName()方法获取方法名,也可以直接调用Method对象的toString()方法直接返回方法的签名

4、使用类对象创建类的对象

①Class类的一个方法:newInstance(),能够通过类的无参构造方法创建一个对象

​ 如:Class c =Student.class;

​ Student stu =(Student)c.newInstance();

二、反射包

以下的几个类都在java.lang.reflect这个反射包内

1、FieId类

封装了属性信息,一个File对象封装了一个属性的信息

①获取特定属性

先获取FieId对象,有两个方法,可以根据属性名获取FieIdduix

1、FieId getDeclaredFieId(String name)

只能获取本类属性,包括本类的非公开方法,不能获得父类的

2、FieId getFieId(String name)

可以获得本类的公开属性以及从父类继承到的公开属性,但无法包括非公开方法

②修改、读取属性

然后根据获得的FieId对象通过反射获取、修改属性的值

先确认修改属性值的三要素:

1、确定要修改哪一个对象的属性;

2、确认要修改对象的哪一个属性;

3、确认要修改的属性值

然后通过FieId对象调用set方法

public void set(Object obj,Object value)

obj:表示要修改属性的对象

value:表示修改后的属性值

例:

1
2
3
4
Student stu =new Student();
Class c = stu.getClass();
FieId nameFieId =c.getFieId("name");
nameFieId.set(stu,"tom");

2.2、私有属性

上面是公开的属性获得方式,还可以获得私有的, 只需要在读取和修改前调用一个方法

public void setAccessible(boolean flag)

1
2
3
4
5
Student stu =new Student();
Class c = stu.getClass()
FieId ageFieId =c.getDeclaredFieId("age");
ageFieId.setAccessible(true);
ageFieId.set(stu,new Integer(18));

2、Method类

①获得特定方法

1
2
public Method getMethod(String name,Class[] parameterTypes);
可以获得公开方法,包括父类的
1
2
public Method getDeclaredMethod(String name,Class[] parameterTypes);
只能获得本类的方法,不包括父类,但是不限于公开的方法

name:表示方法名

Class[] parameterTypes:代表参数列表的数组

②利用反射,调用对象的方法

先确认四要素:

1、确认对哪个对象调用方法

2、确认调用这个对象的哪个方法

3、需要传入的实参

4、方法可以有返回值

先获得即将被调用的方法所对应的Method

3、Constructor类

三、反射的作用