第一章:抽象和封装
学习面向对象,理解其中的概念只是前提,灵活应用才是目的
面向对象编程比较抽象,想要真正掌握,需要一个漫长,积累经验的的过程,在学习中不能操之过急,要多思考,多总结,遇到问题尽量自己解决
面向过程的的核心是函数,以功能为中心,实现了函数级别的代码重用,
面向对象的核心是封装了属性和方法的类,以数据为中心,实现了类级别的代码重用,面向对象因为采用了类,所以具有继承和多态性
面向对象设计的过程就是抽象的过程,分以下三步来完成
第一步:发现类
第二步:发现类的属性
第三步:发现类的方法
面向对象的三大特性:
封装、继承、多态,还有一个抽象(应该是指类)
类(class)和对象(object)是面向对象中的两个核心概念:
类是对一类事物的描述,
是抽象的,对象是实际存在的,是具体的;
类和对象就好比模具和铸件的关系;
一个类可以实例化多个对象,而一个对象只能属于一个类
类主要由属性和行为组成,属性和行为又称为类的成员变量和成员方法
统称为类的成员(除此之外,类的成员的还包括构造方法,代码块{})
封装:将类的状态信息隐藏在类的内部,不允许外部程序直接访问,
而通过该类提供的方法来实现对隐藏信息的操作和访问
像stu.age=200;是不允许的,这个时候就要把字段age封装起来
,使用getter和setter方法封装字段
==》步骤:将字段私有化,接下来按右键,选择源代码(source)-->
选择生成getter和setter
==》好处:可以方便的加入存取控制语句,限制不合理操作
访问修饰符:
private:只可在本类中访问
public:
默认:只能被同一个包里的类访问
protected
:
能被同一个包里的类访问,也可以被不同包中的子类访问
属性
,
方法
,
代码块,内部类
可用static 修饰,但不能修饰普通类
static{
//类的静态修饰的代码块,只在最初调用一次
System.out.println("该类Circle是由我完成编写!");
}
static :
数据在整个程序中只有一个空间,大家共享
通常把
static
修饰的属性和方法称为
类属性
和
类方法,
没用
static
修饰的
属性和方法称为
实例属性
和
实例方法
被申明为static的属性,方法,代码块,
先于实例化的对象而存在,而且是贯穿整个程序
不可以修饰类和局部变量
在加载类的过程中,先完成静态变量的内存分配,再执行静态块
静态的属性或方法可以通过类名或对象名访问
静态的方法中不能使用
this
或
super
关键字
常量:全部大写
类名:每个单词首字母大写
属性名和方法名:第一个单词首字母小写其余首字母大写
构造方法(Constructor)及其重载:
构造方法:
名称和类名相同,没有返回值类型,
如果写了返回值,等同于一般的方法
构造方法的主要作用就是在创建对象时,执行一些初始化操作
面试题常考要注意:构造方法不能被继承,所以不能被重写
还要答出什么是构造器
public class Circle {
private
double
r;
public
Circle
(){}
//无参构造函数
public
Circle(
double
r){
//带参构造函数
this.r = r;
}
//无参构造函数与带参构造函数形成重载关系
}
//注意:当类中一个构造函数也没有的时候,系统会默认提供一个空的构造函数,以上面的例子
public Circle (){}
//但是如果类中已经写了带参构造函数时,默认提供的构造函数会消失
//所以最好将无参构造函数和有参构造函数一起写
重载:
在同一个类中,方法名相同,参数列表不同的方法形成重载。
与方法返回值和方法修饰符无关。
在使用this调用自身的其他构造方法时,只能做第一条非注释语句。
就像这样:
public class Person{
private static String name;
private static int age;
public
Person
() {
this(name,age);//
只能做第一条非注释语句
}
public
Person
(String name,
int
age) {
this.name = name;
this.age = age;
}
}
第二章: 继承
inheritance
:继承
constructor:构造器
abstract:抽象
override:覆盖、重写
overload:重载
继承(inheritance)是Java OOP中一个非常重要的概念。继承是在复用已存在的类的方法和属性
的基础上,还可以添加新的方法和属性
。
Java用extends关键字来表示继承关系(is-a)。被继承的类称为超类(superclass)、基类(base class)、父类(parent class),而新类被称为子类(subclass)、派生类(derived class)或孩子类(child class)。
java支持单继承支持多实现
例如:
Manager is a Employee
class Manager extends Employee{
super
(); 默认调用父类的构造方法,加不加都一样
//Manager 类继承Employee类,同时添加新的方法
//setBonus和新的属性
bonus
public void setBonus(double s){
bonus = s;
}
private double bonus;
}
1. 子类方法覆盖(override)超类方法
假设Manager类继承于Employee类,Employee有name、salary和hireDay三个属性,Manager又新增了bonus一个属性。Employee有方法getSalary(),现在Manager的计算薪水的方式不一样,需要重写getSalary(),以覆盖Employee类的此方法。
需要注意的是子类不能直接访问超类的私有属性(假设salary为私有属性),
那么就不能使用下面这种方法:
public double getSalary(){
return salary + bonus; //error. salary 不能被访问到
}
Java利用另一个方法解决上面这个问题,即使用超类的方法获取属性的值。
public double getSalary(){
return super.getSalary() + bonus;
//super.方法名
}
注释: super不能把它覆给另一个对象变量,
它只是一个指示编译器调用超类方法的特有关键字。
super的另一个应用就是在构造器中。子类构造器需要调用超类的某些构造器
以初始化一些超类的属性(尤其是私有属性)。
public Manager(String n, double s, int year, int month, int day){
//父类已经做完了,子类不必再做了
super(n, s, year, month, day);
bonus = 0;
}
2. 继承层次
由一个公共超类派生出来的所有类的集合被称为继承层次(inheritance hierarchy),
在继承层次中由某个特定类到其祖先的路径被称为该类的继承链(inheritance chain)。
重写与重载有什么区别和联系:
重载:要求方法名相同,参数列表不同即可
重写:方法名、参数列表、返回值类型相同(或是其子类,这里指的是多态)、访问修饰符不能严于父类
3. 多态(polymorphism)和动态绑定(dynamic binding)
一个对象变量可以引用多种实际类型的现象称多态;
在运行时能够自动地选择调用哪个方法的现象称为动态绑定。
例如:
Manager boss = new Manager("boss", 80000, 1987, 12, 15);
boss.setBonus(5000);
Employee[] staff = new Employee[3];
staff[0] = boss;
staff[1] = new Employee("employee_1",50000, 1989,3,23);
staff[2] = new Employee("employee_2",50000, 1990,4,22);
//多态:变量e既可以引用Manager对象,又可以引用Employee对象
//动态绑定:变量e引用Employee对象时调用Employee类的getSalary()方法
//而引用Manager对象时调用Manager类的getSalary()方法
for(Employee e : staff)
System.out.println(e.getName() + " " + e.getSalary());
多态:
Employee e;
e = new Employee(...); //OK
e = new Manager(...); //OK
//但是超类变量不能引用子类对象
Employee a = new Employee(...);
Manager m = a; //error动态绑定:
① 编译器查看对象的声明类型和方法名,获取所有可能被调用的候选方法;对象方法执行过程的详细:
② 编译器查看那调用方法时提供的参数类型,如果与某个候选方法的参数类型完全相同,则选择这个方法。这个过程被称为重载解析(overloading resolution);
③ 前面两步已经获得需要调用的方法名字和参数类型,接下来如果是private方法、static方法、final方法或者构造器,那么编译器将可以准确地知道应该调用哪个方法,这种调用方式被称为静态绑定(static binding)。与此对应的是,调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定;
④ 哪个动态绑定调用方法时,虚拟机一定调用与隐式参数所引用对象的实际类型最合适的那个类的方法。
注:虚拟机为了避免每次都进行搜索方法,所以预先为每个类创建一个方法表(method table),其中列举了所有方法的签名和实际调用的方法。只需查表,所以更快。
4. 阻止继承:final类和方法
将类声明为final,则阻止会其他类对该类进行继承。将类中的方法声明为final,子类就不能覆盖这个方法了。final类中的所有方法自动地称为final方法。
代码如下 | 复制代码 |
final class Executive extends Manager
{
}
class Employee
{
public final String getName()
{
return name;
}
} |
注释:属性也可以声明为final。对于final属性来说,只是在构造对象之后不能再修改它的值而已。我们将方法或者类声明为final的主要原因是确保他们不会在子类中改变语义。有些程序员建议是除非我们有足够的理由使用多态性,否则应该将所有的方法声明为final。这样可以减少动态绑定过程带来的系统开销,提高程序性能。但是,随着Java虚拟机的发展,其处理能力越来越强,编译器已经可以很短的时间内知道类之间的继承关系,并且能够很快地检测出是否存在覆盖的方法。
5. 强制类型转换
•只能在继承层次内进行类型转换
•在将超类转换成子类之前,应该使用instanceof进行检查
代码如下 | 复制代码 |
Employee[] staff = new Employee[3]; staff[0] = new Manager(...); staff[1] = new Employee(...); staff[2] = new Employee(...); Manager boss; if(staff[1] instanceof Manager) { boss = (Manager) staff[1]; } |
6. 抽象类
什么是抽象类?
类是对一类事物的描述,如果一个类中没有包含足够的
信息 来描绘一个具体的对象,那么这个类就是抽象类
什么时候用抽象类?
一般抽象类都是父类基类
抽象类和抽象方法都用abstract关键字声明。不能用来修饰属性和构造方法
抽象类不是不能实例化,而是不能直接实例化,可以通过子类间接实例化
public class ui implements usbInterface{
public void serivce() {
System.out.println("连接USB接口,开始传输数据");
}
}
public interface usbInterface {
void serivce();
}
public
static
void
main(String[] args) {
usbInterface
u=
new
ui();
if(u instanceof usbInterface)
sop("true");
//true
}
面试题:抽象类和接口的区别是什么?何时用抽象类,何时用接口
与接口比较区别:
抽象类表示该类中可能已经有一些方法的具体定义,但是接口就仅仅只能定义各个方法的界面(方法名,参数列表,返回类型),并不关心具体细节。
接口是引用类型的,和抽象类的相似之处有三点:
-
不能直接实例化;
-
包含未实现的方法声明;
-
派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员)。
[2]
抽象类与接口紧密相关。然而接口又比抽象类更抽象,这主要体现在它们的差别上:
-
类可以实现无限个接口,但仅能从一个抽象(或任何其他类型)类继承,从抽象类派生的类仍可实现接口,从而得出接口是用来解决
多重继承问题的。
-
抽象类当中可以存在非抽象的方法,可接口不能,且它里面的方法只是一个声明必须用public来修饰没有具体实现的方法。
-
抽象类中的
成员变量可以被不同的
修饰符来修饰,可接口中的成员变量默认的都是静态
常量(static final)。
-
抽象类是对象的抽象,然而接口是一种行为规范。
抽象类里面可以有非抽象方法但接口里只能有抽象方法 声明方法的存在而不去实现它的类被叫做抽像类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。
然而可以创建一个变量,其类型是一个抽像类,并让它指向具体子类的一个实例。不能有抽像构造函数或抽像静态方法。Abstract 类的子类为它们父类中的所有抽像方法提供实现,否则它们也是抽像类。
取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。
接口(interface)是抽像类的变体。在接口中,所有方法都是抽像的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽像的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对像上调用接口的方法。由于有抽像类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口
何时用抽象类,何时用接口:
共同点是他们都可以实现多态。
不同点在于设计抽象类和接口的目的和使用方式有所不同,抽象类是为继承而精心设计的,接口则更多以组合的方式使用。
如果你的业务中可以抽象出一个通用的处理过程,只是某些局部传递的状态或参数有所不同,这时可以考虑使用抽象类。否则在一般的情况下,优先使用接口和组合的形式,这样使代码之间的耦合度降低。
一个比较典型的抽象类使用范例是模板模式,当然也有使用组合来实现的模板。另一个使用抽象类的情形,比如很多场合下特别是对一个声明了相当数量方法的接口,提供一个类似模板的默认实现类是很有好处的,比如spring提供的一些template,dom4j提供的VisitorSupport等。甚至在effective java里已经将这种方式提倡成一种最佳实践。
abstract不能和private、final、static修饰同一个方法
抽象类中可以有构造方法,用来初始化子类信息
包含一个或多个抽象方法的类必须声明为抽象类。
在抽象类中还可以有属性和具体方法的实现。
抽象方法没有方法体
若要强迫子类重写父类的方法就让父类的方法变成抽象方法
若要让子类不能重写父类的方法就让父类的方法变成最终方法
代码如下 | 复制代码 |
abstract class Person{
public Person(String n) {
name = n;
}
public abstract String getDescription();
public String getName() {
return name;
}
private String name;
} |
一、final
final类不能被继承,没有子类,final类中的方法默认是final的。
不是final类里的final方法不能被子类的方法覆盖,但可以被子类继承。
final不能用于修饰构造方法。final修饰符的主要目的是防止被修改,如父类要防止子类重写其方法,就使用final修饰符
而构造方法子类无法继承,所以使用final修饰符没意义
final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
1、final类
final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的。在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会载被扩展,那么就设计为final类。
2、final方法
如果一个类不允许其子类覆盖某个方法,则可以把这个方法声明为final方法。
使用final方法的原因有二:
1.把方法锁定,防止任何继承类修改它的意义和实现。
2.高效。编译器在遇到调用final方法时候会转入内嵌机制,大大提高执行效率。
3、final变量(常量)
用final修饰的成员变量表示常量,值一旦给定就无法改变!
final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。
从下面的例子中可以看出,一旦给final变量初值后,值就不能再改变了。
另外,final变量定义的时候,可以先声明,而不给初值,这中变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初 始化。但是,final空白在final关键字final的使用上提供了更大的灵活性,为此,一个类中的final数据成员就可以实现依对象而有所不同, 却有保持其恒定不变的特征。
4、final参数
当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。
第三章:多态(polymorphism)
什么是多态?答:不同对象对同一操作的不同实现
子类到父类的转换(向上转型)
父类到子类的转换(向下转型)
使用 父类作为方法的形参实现多态
使用 父类作为方法的返回值实现多态
使用多态的优势:可以减少代码量,提高代码的可扩展性和可维护性
继承是多态的基础,没有继承就没有多态
instanceof 运算符
语法:对象名
instanceof 类或接口
第四章:接口(interface)
防盗门 is a 门 has a 锁 的功能
|----继承
|-----接口(相当于扩展功能)-------------------手机的功能扩展
接口是一套规范和标准,他们可以约束类的行为,是一些方法特征的集合,但是没有方法的实现
抽象类利于代码复用,接口利于代码的扩展和维护
接口类中,定义的是方法,在不同子类中有不同的实现,也就是要被子类重写,接口类的方法就可设计为抽象方法,实现了多态,实现了多实现
接口的命名规则与类名相同,如果修饰符是public,则该接口在整个项目中可见;
如果省略修饰符,则该接口只在当前包可见
接口中可以定义常量,不可以定义变量,接口中的属性都会自动用public static final 修饰 ,即接口中的属性都是全局静态常量,接口中的常量必须在定义时指定初始值
接口中所有的方法都是抽象方法,不得有方法体,不得私有化,因为抽象方法要强迫子类重写其方法,
接口中的方法都会自动用public abstract修饰 ,即接口中的方法都是全局抽象方法
接口不能实例化,不能有构造方法
接口之间可用关键字extends实现继承关系
接口的实现类必须实现接口的的全部方法,否则必须定义为抽象类
extends关键字必须在implements关键字之前
通过以上我们解了接口表示一种能力,一个类实现了某个接口,就表示这个类具备了某种能力
打印机打印小猫小狗,学生、老师、校长、学校等对象,而这个接口必须有传递信息的能力
从使用的角度讲:接口和抽象类的区别在于抽象类利于代码复用,接口利于代码维护,接口类似于一个组件,需要时可以自由组装
继承的时候同时实现
接口表示一种约定:使用接口实现打印机打印
在面向对象编程中提倡面向接口编程,而不是面向实现编程
接口体现了约定和实现相分离的原则,通过面向接口编程,可以降低代码间的耦合性,提高代码的可扩展性和可维护性。面向接口编程就意味着:开发系统时 ,主体架构是使用接口,接口构成系统的骨架,这样就可以通过更换
实现接口的类来实现更换系统
第六章:异常中的throw和
throws
几个常见的异常:
2A:ArithmeticException、ArrayIndexOutOfBounds
Exception
2C:ClassNotFoundException(不是运行时异常)、CalssCastException
2I:InputMismatchException、IllegalArgumentException
2N:NullPointer
Exception、NumberFormatException
常用的异常方法:
void printStackTrace():输出异常的堆栈信息
String getMessage():返回异常信息描述的字符串,该信息只是
printStackTrace():输出信息的一部分
throws :
如果在方法声明的同时声明了可能发生的异常(
throws Exception),throws可以同时声明多个异常类,用逗号分开,父异常类放最后
有两种处理方式:
1:让调用者通过try-catch 捕获并处理异常
2:如果调用者也不打算处理异常,就可以通过throws
继续声明异常,让上一级调用者处理
throw:果在用于方法体内部,抛出的是异常对象
运行时异常:
Check异常(非运行时异常):检查异常:
凡是在API中在构造方法详细信息里有声明异常类型,该异常类型就是检查异常
常见的检查异常有IOExceptin
检查异常必须要做处理,否则编译不通过,处理方式是要么继续声明异常类,要么try
try {
throw new Exception("输入错误!");
} catch (Exception e) {
//
想把项目中出现的异常以文件的形式记录下来
e.printStackTrace(new PrintStream(new FileOutputStream("C:\\Users\\hp\\Desktop\\1.txt"), true));
}
》》》如果想把项目中出现的异常以文件的形式记录下来,甚至记录程序正常运行的关键步骤信息,以便日后查看,就需要使用开源日志记录工具 log4j
开源日志记录工具:log four(for 4) java 缩写 log4j
在项目中创建一个与src同级的
libs目录,然后把相应的jar包复制进来,然后右键这个
jar包,选择构建路径,会生成一个引用的库
接下来就是右键src目录,新建一个文件,文件名为log4j.properties,双击打开这个文件,在下面点击source进行文件配置
/*stdout(Standardoutput)标准输出
stdin(Standardinput)标准输入
stderr(Standarderror)标准错误*/
######
######
### 设置Logger的 输出级别和输出目的###
log4j.rootLogger=info,stdout,fileout
### 把日志信息输出到控制台###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
### 把日志信息输出到文件stu.log ###
log4j.appender.fileout=org.apache.log4j.FileAppender
log4j.appender.fileout.File=stu.log
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.Conversion.Pattern=%d %F %1 %m %n
日志及分类
SQL日志:
异常日志:
业务日志:记录系统运行过程,如用户登录、操作记录
log4j是Apache的一个开源项目,是一个非常优秀的日志记录工具,通过使用log4j,我们可以控制日志输出的级别,以及日志信息输送的目的地,还可以控制每一条日志的输出格式
Logger 对象是用来替代System.out或者System.err的日志记录器
第七章: java 集合框架
List:有序可重复
Set:无序不可重复
Map:无序不可重复
Dog dog=(Dog)list.get(i);必须强转,否则会编译错误!
当长度需要增长时,Vector默认增长为原来的一倍,而ArrayList只增长50%
//先进先出与后进先出
import java.util.*//第一步导入包
class Queue {
private LinkedList list = new LinkedList();//非泛型不安全
public void add(Object obj){
list.addFirst(obj);
}
//先进先出
public Object get(){
Object obj = list.getLast();
list.removeLast();
return obj;
}
//后进先出
public Object get2(){
Object obj = list.getFirst();
list.removeFirst();
return obj;
}
public int size(){
return list.size();
}
@Override
//重写Object的toString方法
public String toString() {
StringBuffer str = new StringBuffer("");
for (Object obj : list) {
str.append(obj.toString()).append(" ");
}
return str.toString();
}
}
public class Test3 {
public static void main(String[] args) {
Queue qu=new Queue();
qu.add("Jack");
qu.add("Lucy");
qu.add("Lily");
qu.add("Tom");
qu.add("Tomas");
System.out.println(qu);
System.out.println(qu.size());
String name = qu.get().toString();//先进先出
// String name = qu.get2().toString();//后进先出
System.out.println(name);
System.out.println(qu);
System.out.println(qu.size());
}
}
int num =Integer.parseInt("36");
boolean Boolean.parseBoolen("true");
第八章:JDBC(Java DataBase Connectivity)
JDBC:Java 数据库连接,由一组类和接口组成,可以为多种关系数据库提供统一的访问。Sun公司(现在已经被Oracle公司收购)提供了JDBC 的接口规范 JDBC API ,而数据库厂商或第三方中间件厂商根据该接口规范提供针对不同不同数据库的具体实现---------JDBC 驱动
JDBC的工作原理:
java的应用程序可以集成在JDK中的java.sql和javax.sql包中的JDBC API 来连接和操作数据库
1:JDBC API 提供了Java 应用程序与各种不同数据库交互的标准接口,如Connection接口、Statement接口、ResultSet接口、PreparedStatement接口、等
2:JDBC Driver Manager:负责管理各种不同的JDBC驱动,位于JDK的java的java.sql包中
3:JDBC 驱动:负责连接各种不同的数据库
JDBC API 主要做三件事:连接数据库、发送sql语句、处理结果
JDBC 访问数据库的步骤:
1:加载驱动
2:与数据库建立连接
3:发送sql语句,并得到返回结果
4:处理返回结果
package com.JulySeven.DAO;
import java.sql.*;
/**
* @author ljh
* 这个类搞定数据库连接和数据库的增删改
* */
public class DataBaseDao {
//创建一个返回一个连接对象的方法
public Connection getCon(){
Connection con=null;
final String URL="jdbc:sqlserver://localhost:1433;DatabaseName=epet";
final String UNAME="sa";
final String UPWD="123";
try {
//加载驱动
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
//与数据库建立连接
con=DriverManager.getConnection(URL,UNAME,UPWD);
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
//关闭所有连接资源
public void closeAll(Connection con,Statement smtm,ResultSet rs){
try {
if(rs!=null){
rs.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if(smtm!=null){
smtm.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if(con!=null
&&!con.isClosed()
){
con.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
//一个方法搞定增删改
public int executeUpdate(String sql,Object[] params){
int result=0;
Connection con=null;
PreparedStatement pstmt=null;
try {
con=getCon();
pstmt=con.prepareStatement(sql);
for(int i=0;i<params.length;i++){
pstmt.setObject(i+1, params[i]);
}
result=pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally{
closeAll(con,pstmt,null);
}
return result;
}
}
---------------------------------------------------------
package com.JulySeven.DAO;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.JulySeven.Entity.Menu;
/**
* 前面的都是铺垫,这个才是真正的数据库访问层
*二级菜单
使用问号作为占位符
* */
//防盗门是一个门有锁的功能
public class MenuImplement extends DataBaseDao implements MenuInterface {
public Map<Integer, List<Menu>> getAllMenu() {
Map<Integer, List<Menu>> map=new HashMap<Integer, List<Menu>>();
Connection con=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try {
con=getCon();
String sql="select * from Menu order by pid";
pstmt=con.prepareStatement(sql);
rs=pstmt.executeQuery();
int myPid=0;
List<Menu> list=new ArrayList<Menu>();
map.put(new Integer(myPid), list);
while(rs.next()){
Menu menu=new Menu(rs.getInt("id"),rs.getString("name"), rs.getInt("pid"));
//myPid会改变
if(menu.getPid()==myPid){
list.add(menu);
}else{
myPid=menu.getPid();
//只new 四次
list=new ArrayList<Menu>();
map.put(new Integer(myPid), list);
list.add(menu);
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
closeAll(con, pstmt, rs);
}
return map;
}
public static void main(String[] args) {
Map<Integer, List<Menu>> map;
MenuImplement m=new MenuImplement();
map =m.getAllMenu();
List<Menu> list=map.get(new Integer(0));
for (Menu menu : list) {
StringBuilder sb=new StringBuilder();
for (Menu m1: map.get(menu.getId())) {
sb.append(m1).append(" ");
}
System.out.println(menu+"::"+sb.toString());
}
}
}
第9章:数据访问层
将大脑中所思考的事情记录到本子上,这个过程就是持久化
相对应的是:内存数据------以文件的形式保存到硬盘
JDBC 就是一种持久化机制,将程序保存成文件也是持久化机制的一种实现,但是通常我们将数据保存到数据库中
进行数据库持久化时采用别人的总结出的解决方案,既可以保证代码的质量,
又可以省去自己摸索的时间,何乐不为
思考一个问题:你用的是别人的方案,万一别人总结的方案不行怎么办?
所以是优先考虑使用别人的
public interface petDaoInterface{
int save (Pet pet);
int del
(Pet pet);
int update (Pet pet);
List<Pet> getAllPet();
}
尽量以对象为单位,而不是以属性为单位来传递参数,给调用者提供面向对象的接口
DAO就是DataAccessObjecs数据存取对象,位于业务逻辑和持久化数据之间,实现对持久哈数据的访问。
DAO模式提供了访问关系型数据库系统所需的的操作接口,将数据访问和业务逻辑分离,对上层提供面向对象数据访问接口。
一个典型的DAO模式主要由DAO接口、
DAO实现类、实体类组成,基于代码的复用考虑,通常创建一个数据库连接和关闭工具类。
使用分层开发便于代码的复用、程序的扩展、降低代码的耦合性、提高开发质量和开发效率。分层开发的种种优势都是建立在合理分层的基础上的,分层时应该坚持封装性原则和顺序访问原则。
在分层结构中,不同层之间通过实体类传输数据。在程序中把实体类作为方法的输入参数或返回结果,实现数据传递,非常方便。
第10章:File IO流
import java.io.*
使用File类操作文件或目录
File类四个重要的方法:
1:boolean exists()//判断文件是否存在
2: long length()//返回文件的长度,若文件不存在,则返回0L
3:
boolean delete()
4: boolean createNewFile()//创建一个空文件,不创建文件夹
通过流来读写文件:
读文件:是指把文件中的数据读取到内存中
写文件:
是指把内存中的数据写入文件中
练习:
将一个GBK编码的文本文件转存为一个UTF-8编码的文本文件。
关键是要用到转换流
import
java.io.*;
public
class
ChangeEncoding {
public
static
void
changeEncoding (String inEncoding, String outEncoding,
String inFileName, String outFileName)
throws
IOException {
BufferedReader reader =
new
BufferedReader(
new
InputStreamReader(
new
FileInputStream(inFileName), inEncoding));
BufferedWriter writer =
new
BufferedWriter(
new
OutputStreamWriter(
new
FileOutputStream(outFileName), outEncoding));
String s =
null
;
while
((s = reader.readLine()) !=
null
) {
writer.write(s,
0
, s.length());
writer.newLine();
}
writer.flush();//一定要刷新缓冲区
writer.close();
reader.close();
}
public
static
void
main(String[] args) {
try
{
changeEncoding(
"GBK"
,
"UTF-8"
,
"gbk.txt"
,
"utf8.txt"
);
}
catch
(IOException e) {
System.out.println(
"转换失败,原因:"
+ e.getMessage());
}
}
}
|
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* @author ljh
* 通过代码从网站上下载一张图片到指定的目录
* */
public class ImageRequest {
public static void main(String[] args) throws IOException {
URL url = new URL("http://pic36.nipic.com/20131128/11748057_141932278338_2.jpg");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//读进来,写出去
InputStream inputStream = conn.getInputStream(); //通过输入流获得图片数据
byte[] getData = readInputStream(inputStream); //获得图片的二进制数据
File imageFile = new File("D://myFirstpic.jpg");
FileOutputStream fos = new FileOutputStream(imageFile);
fos.write(getData);
fos.close();
System.out.println(" read picture successfulluy!");
}
public static byte[] readInputStream(InputStream inputStream) throws IOException {
byte[] buffer = new byte[1024];
int len = 0;
/*这个类实现了一个输出流,其中的数据被写入一个字节数组。当数据被写入时,缓冲区会自动生长。数据可以用toByteArray()和toString()检索。
关闭写入字节数组的输出流没有影响。这个类中的方法可以在流一直没有发生IOException闭叫。*/
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while((len = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
return bos.toByteArray();
}
}
方法摘要 |
---|
void | close() 关闭此流,但要先刷新它。 |
void | flush() 刷新该流的缓冲。 |
void | newLine() 写入一个行分隔符。 |
void | write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 |
void | write(int c) 写入单个字符。 |
void | write(String s, int off, int len) 写入字符串的某一部分。 |
java.io
类 DataInputStream
java.lang.Objectjava.io.InputStreamjava.io.FilterInputStreamjava.io.DataInputStream
所有已实现的接口:
-
Closeable,
DataInput
-
方法摘要 |
---|
int | read(byte[] b) 从包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。 |
int | read(byte[] b, int off, int len) 从包含的输入流中将最多 len 个字节读入一个 byte 数组中。 |
boolean | readBoolean() 参见 DataInput 的 readBoolean 方法的常规协定。 |
byte | readByte() 参见 DataInput 的 readByte 方法的常规协定。 |
char | readChar() 参见 DataInput 的 readChar 方法的常规协定。 |
double | readDouble() 参见 DataInput 的 readDouble 方法的常规协定。 |
float | readFloat() 参见 DataInput 的 readFloat 方法的常规协定。 |
void | readFully(byte[] b) 参见 DataInput 的 readFully 方法的常规协定。 |
void | readFully(byte[] b, int off, int len) 参见 DataInput 的 readFully 方法的常规协定。 |
int | readInt() 参见 DataInput 的 readInt 方法的常规协定。 |
String | readLine() 已过时。 该方法无法将字节正确转换为字符。从 JDK 1.1 开始,读取文本行的首选方法是使用 BufferedReader.readLine() 方法。使用 DataInputStream 类读取文本行的程序可以改为使用 BufferedReader 类,只要将以下形式的代码:
DataInputStream d = new DataInputStream(in);
替换为:
BufferedReader d
= new BufferedReader(new InputStreamReader(in));
|
long | readLong() 参见 DataInput 的 readLong 方法的常规协定。 |
short | readShort() 参见 DataInput 的 readShort 方法的常规协定。 |
int | readUnsignedByte() 参见 DataInput 的 readUnsignedByte 方法的常规协定。 |
int | readUnsignedShort() 参见 DataInput 的 readUnsignedShort 方法的常规协定。 |
String | readUTF() 参见 DataInput 的 readUTF 方法的常规协定。 |
static String | readUTF(DataInput in) 从流 in 中读取用 UTF-8 修改版格式编码的 Unicode 字符格式的字符串;然后以 String 形式返回此字符串。 |
int | skipBytes(int n) 参见 DataInput 的 skipBytes 方法的常规协定。 |