Java基础知识总结,在学习这一门语言新知识点新技术的过程中很枯燥很不容易很有压力,但它必须要经历这些过程,它就是要从认识、模仿、练习、总结、理解与掌握并实际运用的历程;废话少说,请看以下详细文档:
一、基本概念:
1、java语言特点:简单、面向对象、分布式、解析型、稳定、安全、结构中立、易移值、高性能、多线程、动态语言....
2、java环境的搭建
cmd运行java文件
jdk与myeclipse的和Notepad++(超文本编辑器)安装
java编码规范介绍
myeclipse快捷键的使用
java数据类型
数据类型的转换
算数运算符
循环以及分支结构
3、JAVASE的架构:JVM(虚拟机)+JRE(java核心类库)+java编程工具=JDK
4、JDK、SDK、JRE、JVM概念详解:
JDK:(Java 开发包) SDK(软件开发工具) JRE(其实就是java基础类+JVM) JVM(java虚拟机)
5、java语言平台版本:
(1)、javaSE(标准版) 是为开发普通桌面和商务应用程序提供的解决方案,该技术体系是 其他两者的基础,可以完成一些桌面应用程序的开发
(2)、javaME小型版(是为开发电子消费产品和嵌入式设备提供的解决方案)
(3)、javaEE(是为开发企业环境下的应用程序提供的一套解决方案,该技术体系中包含的技 术如 Servlet、Jsp等,主要针对于Web应用程序开发)
6、跨平台解析:有虚拟机(JVM)的出现,只要在不同的电脑装上不同版本的虚拟机就可以到处运行Java的代码
7、编写简单的java程序:
(1)、新建一个文本型的文件
(2)、在文本编写一个类 例如:class Demo{}
(3)、转换文本格式 例如:123.java
(4)、打开cmd 找到该目录下的文件此刻
(5)、编写主方法main 例如:public static void main (String [] args){}
(6)、在主方法输出要显示的内容:System.out.println("Hello World");
8、java运行代码步骤:
(1)、首先cmd运行,接着找磁盘(如e:)成功切换到对应的磁盘
(2)、输入cd 并找到对应的文件输入:E:\mycode
(3)、找到文件之后,输入javac 并输入文件里的.java的超文本(超文本的类方法用 Notepad++自己编辑)
(4)、在同文件夹下生成一个同名不同类型的文本(如:A.class)
(5)、输入java 后再输入类方法名(如:A)回车运行即可输入在文本写的结果
cmd模本代码:
Microsoft Windows [版本 10.0.17134.228]
(c) 2018 Microsoft Corporation。保留所有权利。
C:\Users\QX>e:
E:\>cd E:\mycode
E:\mycode>javac A.java
E:\mycode>java A
Welcome to java
E:\mycode>
9、新建项目步骤:
(1)任务栏右键点击new找到java project 新建
(2)在src里面建包,命名规则(公司域名的倒写,全部小写)如:(com.gx.type)
(3)新建类如(TypeDemo) 命名规则:类名首字母大写(TypeDemo)
(4)新建方法main 命名规则:首字母小写(main、userAdd) 常量命名规则(全部 大写)
10、Java语言的基础组成:关键字(被赋予特殊含义的单词,都是小写形式)
标识符(用于标识某些东西的符号,由26位大小写组成、数字0-9、_或$组成)
注释 (注释:/** 文档注释 */ java特有的)
常量和变量
运算符
语句
函数
数组
11、整数的四表现形式:
二进制:0,1 满2进1
八进制:0-7 满8进1.用0开头表示
十进制:0-9 满10进1 默认进制
十六进制:0-9 A-F 满16进1.用0x开头表示
二、基本数据类型:
基本数据类型取值范围:
数据类型 关键字 内存占用字节数 取值范围 默认值
布尔型 boolean 1个字节(8位) true,false false
字节型 byte 1个字节(8位) -128~127 0
字符型 char 2个字节(16) 0~2的16次方-1 '\u0000'
短整型 short 2个字节(16) -2的15~2的15次方-1 0
整形 int 4个字节(32) -2的31~2的31次方-1 0
长整形 long 8个字节(64) -2的63~2的63次方-1 0
单精度浮点型 float 4个字节(32) 1.40131E-45~3.4028E-38 0.0F
双精度浮点型 double 8个字节(64) 4.9E-324~1.7977E+308 0.0D
byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0
short:短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0
int:整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值0
long:长整型,在内存中占64位,即8个字节-2^63~2^63-1,默认值0L
float:浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0
double:双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0
char:字符型,用于存储单个字符,占16位,即2个字节,取值范围0~65535,默认值为空
boolean:布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false
溢出:正的输出负的,负的输出正(主要原因是超出内存)
包装类:
(boolean Boolean) (byte Byte) (char Character) (short Short) (int Integer) (long Long) (float Float) (double Double)
三、流程控制语句:
if-eles可拆分3中语句:
1、if(){}
2、if(){}eles{}
3、eles if(){} if(){}
switch语句:
switch(表达式){case 表达式值1:语句块1;break;default:语句块;break;}
do while和while语句:
do{} while(){} 语句 (其中都要执行一次)
while(){} 语句
for语句:
for(int i =1;i <11;i++){执行语句;}
使用技巧:当对一个条件进行一次判断时,可以使用if语句。
当对一个条件进行多次判断时,可以使用while语句。
当对某些代码执行很多次是,可以使用循环结构语句
四、运算符:
java中的六种预算符:
1、算术运算符(+ - * / % ++ --)
2、赋值运算符(= += -= *= /= %=)
3、关系运算符(> < >= <= == !=)
4、逻辑运算符(&& || !)
5、位运算符(&与 或| ~非 异或^)
6、三元运算符( ? :)
public static void main(String[] args) {
// 算术运算符:+ - * / % ++ --
// 算术运算符
// + 加 同时也是字符串的连接运算符
int a = 19;
int b = 4;
int c = a + b;
System.out.println("a+b=" + c);
// - 减
int d = a - b;
System.out.println("a-b=" + d);
// * 乘
int e = a * b;
System.out.println("a*b=" + e);
// / 除
int f = a / b;
// 注:整数/整数=整数,是截断取整,而不是四舍五入取整
// ****java.lang.ArithmeticException: / by zero
// int g=a/0; //整数不能除0,
// 当除数或者被除数中有一个为浮点型的,那么结果就是自然除法的结果,
// 如果此时除数为0或者0.0,那么结果为正无穷或者负无穷
// 0.0除0.0结果为NaN 非数
System.out.println("a/b=" + f);
System.out.println("a/0.0=" + (a / 0.0));
System.out.println("-a/0.0=" + (-a / 0.0));
System.out.println("0.0/0.0=" + (0.0 / 0.0));
// % 取余
// 两个整数时 第二个数不能是0
// 一个或者2个为浮点数,第二个数为0或者0.0时,结果为NaN,
// 第一个数为0或0.0时,结果为0.0
int h = a % b;
System.out.println("a % b=" + h);
System.out.println("a % 0.0=" + (a % 0.0));
System.out.println("0.0 & b=" + (0.0 % b));
// ++ 自加 ;单目运算符
int A = 20;
int B = 20;
int C = A++ + B;
System.out.println("++A=" + (++A));
System.out.println("B++=" + (B++));
System.out.println("C=" + C);
// -- 自减,单目运算符
int D = 20;
int E = 20;
System.out.println("--D=" + (--D));
System.out.println("E--=" + (E--));
// 复杂的数学运算在 java.lang.Math
System.out.println("2的3次方=" + Math.pow(2, 3));
System.out.println("4开平方=" + Math.sqrt(4));
// 比较运算符:> >= < <= == !=
System.out.println("5>4 = " + (5 > 4));
System.out.println("5>=4 = " + (5 >= 4));
System.out.println("5<4 = " + (5 < 4));
System.out.println("5<=4 = " + (5 <= 4));
System.out.println("5==4 = " + (5 == 4));
System.out.println("5!=4 = " + (5 != 4));
// == 和 equals 方法
String str = "123";
int intA = 123;
String strA = String.valueOf(intA);
System.out.println("str==strA = " + (str == strA));
System.out.println("str.equals(strA) = " + (str.equals(strA)));
// //逻辑运算符
// &&:与,前后两个操作数必须都是true才返回true,否则返回false。
// &:不短路与,作用与&&相同,但不会短路。
// ||:或,只要两个操作数中有一个是true,就可以返回true,否则返回false。
// |不短路或,作用与||相同,但不会短路。
// !:非,只需要一个操作数,如果操作数为true,则返回false;如果操作数为false,则返回true。
// ^:异或,当两个操作数不同时才返回true,如果两个操作数相同则返回false。
// 短路和不短路
int intB = 10;
if (intB > 11 && intB++ > 9) {
}
System.out.println(intB);
int intC=10;
if(intC<11 || intC++ >9){
}
//!
if (!(1>2)) {
System.out.println("!(1>2)");
}
//^
if (true ^ false) {
System.out.println("true ^ false");
}
System.out.println("intC =" +intC);
//三目运算符: ? :
System.out.println((5>4)?"5>4" :"5<4");
//==和equals
int intA1=10;
int intA2=20/2;
System.out.println("intA1==intA2 :" +(intA1==intA2));
// == 在基本数据类型的时候就是比较值是否相同
// 在引用类型时是比较 地址
//equals 用于判断引用类型的值
String s1="123";
String s2="12"+"34"+"sss"+"sss"+e;
System.out.println(s2);
System.out.println("s1==s2 :" +(s1.equals(s2)));
}
五、数组:
概念:数组就是一种用于存储数据的方式
数据类型:基本数据类型(分:布尔类型和数值类型)、引用数据类型(分:类,接口,数组)
数组的定义:
方法一 type[] arrayName (推荐使用)
方法二 type arrayName[]
数组初始化
1、静态初始化(直接赋值):arrayIntA =new int[]{1,2,3,4,5}
2、动态初始化:arrayStringA =new String[5];
数组的格式:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度]; 示例:int[] arr = new int[5];
实现:1声明数组变量(左边) =创建数组(要使用一个新的关键字.叫做new) (右边)
(注:“=”并不是数学中的“等号”,而是一个赋值运算符)
数组赋值
for(int i =0;i<arrayStringA.length;i++){arrayString.valueOf(i);}
取值
for(int i =0;arrayStringA.length;i++){system.out.println(i);}
foreach(这形式只能取值,不能赋值)
for(String s :arrayStringA){System.out.println(s);}
二维数组
int[][] int1
int1 =new int[][]{{1,2,3,},{4,5,6}}
int1=new int[5][5];
数组的存储
1、定义数组 int[] numbers;
2、分配内存空间 numbers =new int[4]
3、维数组元素指定值 for(int i =0;i<numbers.length;i++){numbers[i]=i*10;}
六、myecilpse环境配置:
在“环境变量”的“系统变量”选项新建系统变量:JAVA_HOME,值为:C:\Program Files\Java\jdk1.7.0(填写你的JDK路径即可)。在系统变量中找到变量“PATH”,双击打开,把以下代码加到变量值末尾:“;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;”(注意最前的”;”不能少 。
说明:
1,.表示当前路径,%JAVA_HOME%就是引用前面指定的JAVA_HOME;
2,JAVA_HOME指明JDK安装路径,此路径下包括lib,bin,jre等文件夹,tomcat,eclipse等的运行都需要依靠此变量。
3,PATH使得系统可以在任何路径下识别java命令。
配置成功之后,在cmd界面输入 java -version 可以查看信息
Tomcat环境配置
下载完成之后,我们解压缩到相应的目录。这里我解压缩到d盘下面
1、然后去配置系统的环境变量,新建系统变量:catalina_home
2、下面两个系统变量如果有,就直接在里面添加,如果没有,大家可以直接创建:将catalina_home加到path里
3、上面的步骤操作完成之后,我们回来Tomcat的bin目录下,找到startup.bat文件,双击运行,就会看到这个界面:Tomcat
4、当里面的命令执行完之后,我们就可以打开浏览器,在里面输入http://localhost:8080/ 就可以看到如下界面:
以上步骤完成后,我们的Tomcat就搭建好了,但是通过这种方式启动,在我们关闭命令行窗口时,Tomcat就停止了。
设置工作空间编码格式:
点击Windows → preference → WorkSpace(选择编码格式,默认为GBK,不过选择UTF-8为好)
更改字体:
点击Windows → preference → General →Appearence → Color and Fonts → Basic
或者搜索Colors and fonts
选择 Text font ,点击Edit编辑,就可以更改字体了,选择合适的就行
Class类的注释模板:
打开Eclipse/MyEclipse工具,点击 Window->Preferences弹出首选项设置窗口,Java->Code Style->Code Template选项列表,点击Types
添加Tomcat:
点击Windows → preference →MyEclipse →Server → Tomcat 或者搜索tomcat
选择tomcat的版本并导入响应版本的tomcat
显示行号:
右键代码最左边,选中Show line Number
导入项目:
在项目框右键import,选择General→Existing projects to workspace,然后选择项目的路径。如果是maven项目,则是用mavan导入就行。至于是否copy到工作空间,这看个人选择
导出项目:
如果只是项目普通的导出,那就直接右键项目,选择copy就行。如果是要在tomcat部署或者导出为架包,则选择war和jar方式导出
切换工作空间:
File→ switch workspace 然后选择要切换的路径。切换之后,myeclipse/eclipse回重启
Tomcat添加项目:
在server窗口中添加(选择tomcat,右键Add Deployment,选择要添加的项目,然后点击Finsh就OK了)
取消自动validation:
除开Manual下面的复选框全部选中之外,其他全部不选
七、所有变量:
成员变量:在类体里面定义的变量叫做成员变量;
如果在变量有static关键字修饰,就叫作静态变量或类变量;如果没有,就叫非静态变量或实例变量
1、类变量(以static修饰)
2、实例变量(不以static修饰)
局部变量:方法内定义的变量、形参、代码块中定义的变量都叫做局部变量;
1、形参(方法签名中的定义的变量)
2、方法局部变量(在方法内定义)
3、代码块局部变量(在代码块内定义)
另外,成员变量可以不显式初始化,它们可以由系统设定默认值;局部变量没有默认值,所以必须设定初始赋值。
还有,在内存中的位置也不一样。成员变量在所在类被实例化后,存在堆内存中;局部变量在所在方法调用时,存在栈内存空间中。
总结:
在类下面的以及有无static关键字修饰的都称为成员变量分别有两种方式定义:类变量、实例变量
在方法里面的形参定义及方法体里面的以及代码块里面的变量称为局部变量
八、封装:
封装:Encapsulation(是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法)
继承、封装、多态、抽象是面向对象编程的四大基本概念,其中封装尤为重要,因为从我们学习JAVA开始,就基本上接触了封装,因为JAVA中的所有程序都是写在类中的,类也能当做一种封装。
为什么要封装的解释:
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性
在面向对象中封装是指隐藏对象的属性和实现的细节,仅对外提供公共访问方式。在类定义中用private关键字来实现封装。封装有什么好处?
(一)、是用private把类的细节与外界隔离起来,从而实现数据项和方法的隐藏,而要访问这些数据项和方法唯一的途径就是通过类本身,类才有资格调用它所拥有的资源(方法,数据项属性等等)。所以第一个好处就是数据的安全性提高了。
(二)、是通过隐藏隔离,只允许外部对类做有限的访问,开发者可以自由的改变类的内部实现,而无需修改使用该类的那些程序。只要那些在类外部就能被调用的方法保持其外部特征不变,内部代码就可以自由改变,各取所需,利于分工。
(三)、就是提高了代码的重用性,封装成工具类以后能够减少很多繁琐的步骤
封装的优点:
1. 良好的封装能够减少耦合。
2. 类内部的结构可以自由修改。
3. 可以对成员变量进行更精确的控制。
4. 隐藏信息,实现细节。
/*
* java封装示例
*
* get,set快捷键 alt+shift+s
*
* 重复三次使用要有封装的思想
*
*/
public class Encapsulation {
private String name;
private int age;
private int sex;
//快捷键 alt+shift+s 然后选择....setters进行添加
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
}
九、继承:
(一)、继承的概念:
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为
(二)、类的继承格式:
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下
class 父类{}
class 子类 extends 父类 {}
(三)、继承类型:
需要注意的是 Java 不支持多继承,但支持多重继承
单继承 多继承 不同类型继承同一个类 (java不支持多继承)
(四)、继承的特性:
子类拥有父类非private的属性,方法。
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法。
Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如A类继承B类,B类继承C类,所以按照关系就是C类是B类的父类,B类是A类的父类,这是java继承区别于C++继承的一个特性。
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
(五)、继承关键字:
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类
1、extends关键字(在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类)
示例:
public class Animal {
private String name;
private int id;
public Animal(String myName, String myid) {
//初始化属性值
}
public void eat() { //吃东西方法的具体实现 }
public void sleep() { //睡觉方法的具体实现 }
}
public class Penguin extends Animal{ }
2、implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)
示例:
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {}
3、super与this关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用
4、final关键字
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写
声明类:final class 类名 {//类体}
声明方法:修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}
十、访问控制级别和修饰符
private (同一个类中)私有的
default (同一个类中、同一个包)受权限的
protected (同一个类中、同一个包、子类中)继承的类可以访问
public (同一个类中、同一个包、子类中、全局范围内)公有的
访问控制修饰符
**类:
* 访问修饰符:public
* 修饰符:abstract
final
**变量:
* 访问修饰符:
public (可以被任何类访问)
protected (可以被同一包中的所有类访问 和 被所有子类访问)
default (可以被同一包中的所有类访问 注:如果子类没有在同一个包中,也不能访问)
private (只能够被当前类的方法访问)
* 修饰符:
static (静态变量(又称为类变量,其它的称为实例变量),可以被类的所有实例共享。并不需要创建类的实例就可以访问静态变量)
final
**方法:
* 访问修饰符:
public (可以从所有类访问)
protected (可以被同一包中的所有类访问 和 被所有子类访问)
default (可以被同一包中的所有类访问 注:如果子类没有在同一个包中,也不能访问)
private (只能够被当前类的方法访问)
* 修饰符:
static (静态方法(又称为类方法,其它的称为实例方法),提供不依赖于类实例的服务,并不需要创建类的实例就可以访问静态方法)
final (防止任何子类重载该方法)
abstract (抽象方法,类中已声明而没有实现的方法,不能将static方法、final方法或者类的构造器方法声明为abstract)
十一、多态:
重载(overload):
方法重载的作用:方法重载就是对不同数据类型的的数据实现相似的操作
方法重载的定义:对于同一个类,如果这个类里面有两个或者多个重名的方法,但是方法的参数个数、类型、顺序至少有一个不一样,这时候局构成方法重载
Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。
调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性
示例一:
public class Test{
public void a( ){
};
public void a( int i){
};
}
说明:在Test类中有两个方法,名字都相同,都是a。在调用方法a时,如果不传参数,则系统会自动调用第一个方法a,如果传入一个 int 类型的参数,则系统调用第二个方法a。
示例二:
public class Test{
public void a(int i){
};
public void a(String j){
};
}
说明:在Test类中有两个同名的方法a。在调用方法时,如果传入一个int类型的参数,则会自动调用第一个a方法,如果传入一个String类型的参数,则会自动调用第二个方法a。
示例三:
public class Test{
public void a(int i,String j){
}
public class a(String j,int i){
}
}
说明:在Test类中有两个同名的方法。在调用方法时,如果传入的第一个参数类型为int,第二个参数类型为String,则自动调用第一个方法a。如果传入的第一个参数为String类型,第二个参数类型为int,则自动调用第二个方法a。
重写(override):
当一个类继承另一个类时,则可以拥有父类的成员方法和成员变量,在子类中,可以创建独有的成员,如果创建了一个与父类中相同名称,相同返回类型、相同参数列表的方法,只是方法体中的实现方法不同,以实现不同于父类的功能,这种方式就称为方法的重写,又称为方法的覆盖
解释:所谓方法重写就是子类的方法和父类中继承下来的方法具有完全相同的方法名、返回值类型、方法的参数个数以及参数类型,这样才能被称为方法重写
在进行方法重写的时候需要遵循以下规则才能实现方法重写:
1、子类方法的参数列表必须和父类中被重写的方法的参数列表相同(参数个数和参数类型),否则只能实现方法的重载。
2、子类方法的返回值类型必须和父类中被重写的方法返回值类型相同,否则只能实现方法重载。
3、在Java规定,子类方法的访问权限不能比父类中被重写的方法的访问权限更小,必须大于或等于父类的访问权限。
4、在重写的过程中,如果父类中被重写的方法抛出异常,则子类中的方法也要抛出异常。但是抛出的异常也有一定的约束--->子类不能抛出比父类更多的异常,只能抛出比父类更小的异常,或者不抛出异常。例如:父类方法抛出Exception,那么子类就只能抛出IOException或者抛出比Exception小的异常或者不抛出异常。
示例:
package com.gx.extendsdeom;
/*
* 这是父类的定义
*/
public class Person {
public void eat() {
System.out.println("=====你爸爸叫你吃饭了=======");
}
public void sleep(){
System.out.println("=====你爸爸叫你睡觉了=======");
}
}
package com.gx.extendsdeom;
/*
* 这是子类的定义并输出结果
* 子类重写父类的方法后,在实例化子类的时候则调用的是子类中的方法,父类的方法就如同被覆盖了一样。
* 如果在子类中需要调用父类的方法,则在子类方法中使用super关键字调用父类的方法,格式:super.父类中的方法名(参数列表)
*
*/
public class Student extends Person {
@Override
public void eat() {
System.out.println("===你爸爸叫你吃饭了===");
}
@Override
public void sleep(){
System.out.println("=====你爸爸叫你睡觉了=======");
}
// main方法测试
public static void main(String[] args) {
Student student = new Student();
student.eat(); //输出:===你爸爸叫你吃饭了===
student.sleep(); //=====你爸爸叫你睡觉了=======
}
}
十二、进制转换:
一 二 三 四 五 六 七 八 九 十 十一 十二 十三 十四 十五 十六
0 1 2 3 4 5 6 7 8 9 A B C D E F
如何实现进制之间的转换,你可以选择任何一种进制为基准,然后在进行转换,本例主要是以10进制为中间位,根深蒂固的一些问题。一些具有特殊关系的进制之间转换可以,2进制和他的2N进制;例如8进制的12 ,我们可以把他搞成2进制来看待, 0001 0010 ,然后把10010这个就是8进制12转换为2进制的结果
实现过程:
1、把任意一个进制转换为10进制,这个是相当容易的。例如我有X进制的ABCD 。我把他转换为10进制就等于 A*X3+B*X2+C*X+D;
2、然后再把10进制转换成你要转换成的进制数,参考下图计算规则:
整数的四表现形式:
二进制:0,1 满2进1
八进制:0-7 满8进1.用0开头表示
十进制:0-9 满10进1 默认进制
十六进制:0-9 A-F 满16进1.用0x开头表示
十进制
2560=2*10^3+5*10^2+6*10^1+0*10^0
abcd=a*10^(4-1)+b*10^(3-1)+c*10^(2-1)+d*10^(1-1)
二进制
1111=1*2^(4-1)+1*2^(3-1)+1*2^(2-1)+1*1
=8+4+2+1
=15
八进制
7777=7*8^3+7*8^2+7*8^1+7*1
=7*512+7*64+7*8+7
=3584+448+56+7
=4095
十六进制
FF =15*16+15
=240+15
=255
二进制->十进制:
第一步:写2
第二步:标指数。从右向左,从0开始依次标记
第三步:乘系数。一一对应
第四步:相加。
例:二进制数:1101,转十进制。
第一步: 2 2 2 2
第二步: 2^3 2^2 2^1 2^0
第三步: 1*2^3 1*2^2 0*2^1 1*2^0
第四步: 1*2^3+1*2^2+0*2^1+1*2^0=13
口算方法:8 4 2 1
十进制->二进制:除2取余
第一步:用竖式,对十进制数依次除2,记录每一步余数。
第二步:一直除到商0为止,从下倒上记录余数,即是2进制数。
进制转换:
752=2*10(0)+5*10(1)+7*10(2)
1011=1*2(0)+1*2(1)+0*2(2)+1*2(3)
=1 + 2 + 0 + 8 =11
二进制数:0 1 0 1 0 1 1
结果: 64 32 16 8 4 2 1 =43
111=7 1111=15 11111=31 1111-1111
010-101-110
2 5 6 八进制表示:0256
-1010-1110
10 14 十六进制表示:0xAE
6 / 2 =2余:0
3 / 2 =1余:1
1 / 2 =0余:1
结果:6=110
结论:八进制数,其实就是二进制位3个二进制位一个八进制位。
十六进制:其实就是二进制中的四个二进制位为一个十六进制位。
负数的进制:
其实就是这个数的正数的二进制取反,加1
-6
0000-0110
取反1111-1001
+ 0000-0001
------------------
1111-1010 -6
负数的二进制的最高位是1
1011 =11
+0110 =6
----------
10001 ==17
11+6 = 17
十三、初始化块:
初始化块(initializationblock)
执行顺序:静态初始化块,初始化块,构造器
属性、方法、构造方法和自由块都是类中的成员,在创建类的对象时,类中各成员的执行顺序:
1.父类静态成员和静态初始化快,按在代码中出现的顺序依次执行。
2.子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
3. 父类的实例成员和实例初始化块,按在代码中出现的顺序依次执行。
4.执行父类的构造方法。
5.子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
6.执行子类的构造方法。
一个类中可以有多个静态初始化块和多个普通初始化块;
静态初始化块的执行要早于普通初始化块;
同一个类型的初始化块的执行顺序取决于定义的先后顺序
示例:
public class Test {
/**
* Description
* @param args
*/
public static void main(String[] args) {
Son s = new Son();
}
}
class Parent{
{
System.out.println("parent中的初始化块");
}
static{
System.out.println("parent中static初始化块");
}
public Parent(){
System.out.println("parent构造方法");
}
}
class Son extends Parent{
{
System.out.println("son中的初始化块");
}
static{
System.out.println("son中的static初始化块");
}
public Son(){
System.out.println("son构造方法");
}
}
十四、单例类:
代码包名:singleton
单例模式有以下特点:
1、单例类只能有一个实例
2、单例类必须自己创建自己的唯一实例
3、单例类必须给所有其他对象提供这一实例
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
//隐藏构造器
private Singleton() {}
//实例化
private static Singleton single=null;
//静态工厂方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
注意:Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问
1、在getInstance方法上加同步
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
2、双重检查锁定
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
3、静态内部类
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
//饿汉式单例类.在类初始化时,已经自行实例化
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的
两者之间的区别:
饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了,
而懒汉比较懒,只有当调用getInstance的时候,才回去初始化这个单例
以及线程安全和资源加载和性能的不同
十五、final修饰符:
final从字面上理解含义为“最后的,最终的”。在Java中也同样表示出此种含义
final修饰符:
1、final修饰成员变量 (实例变量和类变量(静态变量))---无法赋值(可以初始化)
2、final修饰局部变量----只能赋值一次(相对于初始化变量)
3、final修饰方法----不能被重写override
4、final修饰类----Sting就是一个被final修饰的类,我们只能用,不用继承 注意:(面试题经常问道)
final修饰成员变量示例:
public class FinalMemberVariables {
// final 修饰的实例变量
// 必须在非静态初始化块、声明该实例变量或构造器中指定初始值,
// 而且只能在三个地方的其中之一指定。
//声明该实例变量指定初始值
final int INT_A=10;
//初始化块指定初始值
final int INT_B;
{
INT_B=11;
}
final int INT_C;
//构造器中指定初始值
public FinalMemberVariables(){
INT_C=12;
}
//final 修饰 类变量
//必须在静态初始化块中指定初始值或声明该类变量时指定初始值,
//而且只能在两个地 方的其中之一指定。
final static String STR_A="123";
final static String STR_B;
static{
STR_B="123456";
}
}
final局部变量示例:
public class FinalLocalVariable {
//final修饰局部变量时,既可以在定义时指定默认值,也可以不指定默认值。
public static void main(String[] args) {
//在定义时指定默认值
//不能再后面的代码中为变量赋值
final int intA=10;
//下面的赋值语句非法
//intA=12;
//定义时不指定默认值
//可以在后面的代码中赋值一次
final String strA;
strA="123";
//下面的赋值语句非法
//strA="456";
}
public void test(final int num){
// 不能对final修饰的形参赋值
//num=10;
}
}
final的修饰方法示例:
public class B extends A {
public static void main(String[] args) {
}
public void getName() {
}
}
class A {
//因为private修饰,子类中不能继承到此方法,因此,子类中的getName方法是重新定义的、属于子类本身的方法,编译正常
private final void getName() {
}
/* 因为pblic修饰,子类可以继承到此方法,导致重写了父类的final方法,编译出错
public final void getName() {
}
*/
}
十六、抽象类
(一)、抽象类的基本概念:
普通类是一个完善的功能类,可以直接产生实例化对象,并且在普通类中可以包含有构造方法、普通方法、static方法、常量和变量等内容。
而抽象类是指在普通类的结构里面增加抽象方法的组成部分
(二)、什么是抽象类:
在所有的普通方法上面都会有一个“{}”,这个表示方法体,有方法体的方法一定可以被对象直接使用。
而抽象方法,是指没有方法体的方法,同时抽象方法还必须使用关键字abstract做修饰
(三)、抽象类的定义:
abstract class A{//定义一个抽象类
public void fun(){//普通方法
System.out.println("存在方法体的方法");
}
public abstract void print();//抽象方法,没有方法体,有abstract关键字做修饰
}
(四)、抽象类的使用原则如下:
1、抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public;
2、抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理;
3、抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类;
4、子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。)
(五)、抽象类的示例:
第一步:
package com.gx.abstractdemo;
/**
* Animal 动物抽象类 抽象类不能创建实例,只能当成父类来被继承。
* 1、抽象类必须使用abstract修饰符来修饰,
* 抽象方法也必须使用abstract修饰符来修饰,
* 抽象方法不能有方法体。
* 2、抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。
* 3、抽象类可以包含成员变量、
* 方法(普通方法和抽象方法都可以)、
* 构造器、初始化块、
* 内部类(接 口、枚举)5种成分。
* 抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
* 4、含有抽象方法的类只能被定义成抽象类。
* abstract static不能同时修饰一个方法
*/
public abstract class Animal {
protected int weight =0;
{
System.out.println("初始化块");
}
// 定义一个普通方法 休息
public void sleep() {
System.out.println("休息");
}
public Animal(){
System.out.println("Animal 无参的构造器");
}
public Animal(int weight) {
this.weight=weight;
System.out.println("Animal 有参的构造器");
}
//抽象方法 没有方法体
public abstract void running();
public abstract String sayWeiget();
}
第二部:
package com.gx.abstractdemo;
public class Rabbit extends Animal {
public Rabbit(int weight){
super(weight);
System.out.println("Rabbit 构造器");
}
@Override
public void running() {
System.out.println("兔子蹦蹦跳跳");
}
@Override
public String sayWeiget() {
return "兔子体重"+weight+"kg";
}
}
第三部输出结果:
package com.gx.abstractdemo;
public class ShuChuDemo {
public static void main(String[] args) {
Rabbit rabbit=new Rabbit(5);
rabbit.running();
System.out.println(rabbit.sayWeiget());
//并不是创建的Animal的对象
Animal animal=new Animal() {
@Override
public String sayWeiget() {
// TODO Auto-generated method stub
return null;
}
@Override
public void running() {
// TODO Auto-generated method stub
}
};
Animal animal2=new Rabbit(12);
animal2.running();
}
}
十七、接口:
(一)、接口介绍:
1、接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
2、接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
3、除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
4、接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
(二)、接口与类相似点:
1、一个接口可以有多个方法。
2、接口文件保存在 .java 结尾的文件中,文件名使用接口名。
3、接口的字节码文件保存在 .class 结尾的文件中。
4、接口相应的字节码文件必须在与包名称相匹配的目录结构中。
(三)、接口与类的区别:
1、接口不能用于实例化对象。
2、接口没有构造方法。
3、接口中所有的方法必须是抽象方法。
4、接口不能包含成员变量,除了 static 和 final 变量。
5、接口不是被类继承了,而是要被类实现。
6、接口支持多继承。
(四)、接口特性:
1、接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
2、接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
3、接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
(五)、抽象类和接口的区别:
1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
(六)、接口的声明语法格式如下:
[可见度] interface 接口名称 [extends 其他的接口名名] {
// 声明变量
// 抽象方法
}
(七)、接口的实现
1、当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
2、类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。
实现一个接口的语法,可以使用这个公式:
Animal.java 文件代码:
...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...
实例
MammalInt.java 文件代码:
/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
(八)、接口的继承
一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。
下面的Sports接口被Hockey和Football接口继承:
// 文件名: Sports.java
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
// 文件名: Football.java
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
// 文件名: Hockey.java
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类需要实现六个方法。
相似的,实现Football接口的类需要实现五个方法,其中两个来自于Sports接口。
(九)、接口的多继承
在Java中,类的多继承是不合法,但接口允许多继承。
在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。 如下所示:
public interface Hockey extends Sports, Event
以上的程序片段是合法定义的子接口,与类不同的是,接口允许多继承,而 Sports及 Event 可能定义或是继承相同的方法
十八、集合排序:
(一)、java集合的工具类Collections中提供了两种排序的方法,分别是:
1、自然排序:Collections.sort(List list)
解释:参与排序的对象需实现comparable接口,重写其compareTo()方法,方法体中实现对象的比较大小规则
示例如下:
package com.gx.collectiondemo;
/*
* 自然排序:Collections.sort(List list)
* Comparable 排序接口是在类的内部实现
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class ListComparable {
public static void main(String[] args) {
List<PersonComparable> persons = new ArrayList<PersonComparable>();
persons.add(new PersonComparable("小A", 35));
persons.add(new PersonComparable("小B", 25));
persons.add(new PersonComparable("小C", 25));
persons.add(new PersonComparable("小D", 12));
persons.add(new PersonComparable("小X", 33));
persons.add(new PersonComparable("小M", 33));
persons.add(new PersonComparable("小E", 33));
// 第三步 调用sort 排序
Collections.sort(persons);
Iterator<PersonComparable> iterator = persons.iterator();
while (iterator.hasNext()) {
PersonComparable persion = iterator.next();
System.out.println(persion.getName());
}
}
}
// 第一步 :实现接口Comparable<T>
class PersonComparable implements Comparable<PersonComparable> {
private int age;
private String name;
public PersonComparable() {
}
public PersonComparable(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 第二步 实现compareTo方法 o 表示和当前对象比较的另外一个对象
@Override
public int compareTo(PersonComparable o) {
// 从小到大 :this-o
// 从大到小:o-this
// return this.age - o.age;
if (this.age != o.age) {
return this.age - o.age;
} else {
return this.name.compareTo(o.name);
}
}
}
2、定制排序或自定义排序:Collections.sort(List list,Comparator c)
解释:需编写匿名内部类,先new一个Comparator接口的比较器对象c,同时实现compare()其方法;后将比较器对象c传给Collections.sort()方法的参数列表中,实现排序功能;
示例如下:
package com.gx.collectiondemo;
/*
* 定制排序或自定义排序:Collections.sort(List list,Comparator c)
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
public class ListComparator {
public static void main(String[] args) {
List<PersonComparator> persons = new ArrayList<PersonComparator>();
persons.add(new PersonComparator("小A", 35));
persons.add(new PersonComparator("小B", 25));
persons.add(new PersonComparator("小C", 25));
persons.add(new PersonComparator("小D", 12));
persons.add(new PersonComparator("小X", 33));
persons.add(new PersonComparator("小M", 33));
persons.add(new PersonComparator("小E", 33));
//调用sort 排序
Collections.sort(persons,new Comparator<PersonComparator>() {
@Override
public int compare(PersonComparator o1, PersonComparator o2) {
//从小到大:o1-o2
//从大到小:o2-o1
if (o1.getAge()!=o2.getAge()) {
return o1.getAge()-o2.getAge();
} else {
return o2.getName().compareTo(o1.getName());
}
}
});
Iterator<PersonComparator> iterator = persons.iterator();
while (iterator.hasNext()) {
PersonComparator persion = iterator.next();
System.out.println(persion.getName());
}
}
}
class PersonComparator {
private int age;
private String name;
public PersonComparator() {
}
public PersonComparator(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
十九、集合:
Java集合类存放于 java.util 包中,是一个用来存放对象的容器
Collection 一组"对立"的元素,通常这些元素都服从某种规则
├---List
│ ├--LinkedList(实现类)
│ ├--ArrayList(实现类)
│ └--Vector(实现类)
└---Set
├---HashSet(实现类)
├---TreeSet(实现类)
Map 一组成对的"键值对"对象
├---HashMap
├---HashTable
└---TreeMap
// 添加
list3.add("E");
list2.add("Q");
// 修改
list2.set(0, "QQ");
// 移除
list.remove(1);// 通过索引移除
list.remove("D");// 通过对象移除
list.removeAll(list3);// 移除多个
//引用方法
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import java.util.HashSet;
(一).集合的体系结构:
1、List,Set,Map是集合体系中最主要的三个接口
其中list和set是继承自collection接口
Map也属于集合系统但是与collection接口不同
2、list是有序且允许元素重复,允许元素为null,ArrayList、LinkedList和Vector是三个主要的实现类
(1)、Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。
(2)、Vector线程安全的(同步),ArrayList、LinkedList线程不安全的(不同步)。
(3)、ArrayList、Vector适合查找,不适合指定位置的插入、删除操作;LinkedList适合指定位置插入、删除操作,不适合查找。
(4)、ArrayList在元素填满容器时会自动扩充容器大小的50%,而Vector则是100%,因此ArrayList更节省空间
3、set是无序,不允许元素重复,只有新增和移除;HashSet和TreeSet是两个实现类
(1)、HashSet 基于HashMap实现,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的
(2)、TreeSet 是二叉树实现的,Treeset中的数据是自动排好序的,不允许放入null值
4、Comparator 和 Comparable 的区别
Comparator 定义在 类的外部, 此时我们的类的结构不需要有任何变化,从小到大:o1-o2 从大到小:o2-o1
Comparable 定义在 类的内部,耦合性较强 从小到大 :this-o 从大到小:o-this
5、Map是接口,Map特性就是根据一个对象查找对象;HashMap、HashTable、TreeMap是它的实现类
HashMap 线程不安全,key,value允许为null,用hash表实现的Map,就是利用对象的hashcode(hashcode()是Object的方法)进行快速散列查找.
HashTable 线程安全,key,value不允许为null
TreeMap 线程不安全,根据key对节点进行排序,保证所有的key-value处在有序状态,key不允许为null
6、为了线程安全而提出,线程安全的就是同步的,不安全的就是不同步的;不同步的运行速度要比同步的快,这是因为有锁的机制存在
(二)、集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。所以的集合类都位于java.util包下,后来为了处理多线程环境下的并发安全问题,java5还在java.util.concurrent包下提供了一些多线程支持的集合类
(三)、Collection和Map的区别在于容器中每个位置保存的元素个数:
1、Collection 每个位置只能保存一个元素(对象)
2、Map保存的是"键值对",就像一个小型数据库。我们可以通过"键"找到该键对应的"值"
二十、常用类:
System
RunTime
String StringBuffer StringBuilder
Math
BigDecimal
Date Calendar
Random
(一)、System类
1、System类是一个特殊类,它是一个公共最终类,不能被继承,也不能被实例化,即不能创建System类的对象
2、System类包含三个使用频繁的公共数据流,分别是:标准输入(in)、标准输出(out)、标准错误输出(err)
3、获取当前时间的例子:
使用currentTineMillis( )可以记录程序执行的时间,这是一个特别有意义的用法。currentTineMillis( )方法返回自从1970年1月1日午夜起到现在的时间,时间单位是毫秒。如果要记录程序中一段有问题程序的运行时间,可以在这段程序开始之前调用currentTineMillis( )方法存储当前时间,在这段程序结束处再次调用currentTineMillis( )方法。执行该段程序所花费的时间为其结束时刻的时间值减去其开始时刻的时间值。下面的程序段可以用来估计一下执行某个循环所占用的时间:
long startTime=System.currenTimerMillis( );//记录循环开始时间
int sum=0;
for(int i=0;i<100000;i++){
sum+=i;
}
long endTime=System.currentTimeMillis( );// 记录循环结束时间
System.out.Println("time: "+(endTime-startTime)+ "milliseconds. ");
4、快速复制数组
5、退出虚拟机:
在用户的程序还未执行完之前,强制关闭Java虚拟机的方法是exit():
Public static void exit(int exitCode)
关闭虚拟机的同时把状态信息exitCode传递给操作系统,exitCoded非零时,表示非正常退出。
6、强制垃圾收集:
垃圾收集器一般情况下运行于后台,并自动地收集已不使用了的内存。使用gc()方法可强制垃圾收集器启动:
public static void gc();
(二)、RunTime类(Runtime:运行时,是一个封装了JVM的类)
1、Runtime类代表Java程序的运行时环境,每个Java程序都有一个与之对应的Runtime实例, 应用 程序通过该对象与其运行时环境相连
2、应用程序不能创建自己的Runtime实例,但可以通过getRuntime()方法获取与之关联的Runtime对象
3、使用Runtime获取JVM的空间信息
示例:
public class RuntimeDemo01{
public static void main(String[] args){
Runtime run = Runtime.getRuntime(); //通过Runtime类的静态方法获取Runtime类的实例
System.out.println("JVM最大内存量:"+run.maxMemory());
System.out.println("JVM空闲内存量:"+run.freeMemory());
String str = "Hello"+"World";
System.out.println(str);
for(int i=0;i<2000;i++){
str = str + i;
}
System.out.println("操作String之后的JVM空闲内存量:"+run.freeMemory());
run.gc();
System.out.println("垃圾回收之后的JVM空闲内存量:"+run.freeMemory());
}
}
(三)、String、StringBuffer、StringBuilder类
1、String是不可改变的,但StingBuffer和StringBuilder是可以改变的。在操作时,String会在常量池中开辟多个新的空间,StingBuffer和StringBuilder直接改变值,大大降低了对空间的浪费
String类的判断、获取、转换、替换功能
至于如何使用String类型,有两种方法,一是直接赋值,二是用 new 创建,具体示例如下:
// 1、直接赋值
String str1 = "维C果糖";
// 2、用 new 运算符创建
String str2 = new String("维C果糖");
三者在执行速度方面的比较:*StringBuilder > StringBuffer > String
StringBuffer和StringBuilder类是可以通过append()、insert()、reverse()....等方法来修改值
2、StringBuffer:线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容
3、StringBuilder:一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快
4、通常情况不同类型做形式参数:
基本类型:形式参数的改变不影响实际参数
引用类型:引用参数的改变直接影响实际参数
示例:
public class StingBufferTest {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
System.out.println(s1+"---"+s2);//hello---world
change(s1,s2);
System.out.println(s1+"---"+s2);//hello---world
StringBuffer buffer1 = new StringBuffer("hello");
StringBuffer buffer2 = new StringBuffer("world");
System.out.println(buffer1+"---"+buffer2);//hello---world
change2(buffer1,buffer2);
System.out.println(buffer1+"---"+buffer2);//hello---worldworld
}
public static void change(String s1, String s2) {
s1 = s2;
s2 = s1 + s2;
}
public static void change2(StringBuffer buffer1, StringBuffer buffer2) {
buffer1 = buffer2;
buffer2.append(buffer1);
}
}
通过断点调试可以得出结论:
String做形式参数的效果和基本类型做形式参数的效果相同,因为它和其它的引用类型存储方式不一样,直接从栈中指向方法区中的静态常量池;StringBuffer可以通过调用方法可以直接影响实际参数
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
(四)、BigDecimal、BigInteger类
1、为什么为用到BigInteger和BigDecimal这种数据类型呢?
我们非常清楚,Java里面整型int与浮点型float,double它们存放数据的范围是有边界的。那么如果需要更大的数据时,这些数据类型肯定是满足不了这种需求,所以就用到了BigInteger和BigDecimal来解决这个问题
2、BigInteger与BigDecimal这两个类是什么包里面的?它们的作用分别是什么?
java.math包
BigInteger实现了任意精度的整数运算;
BigDecimal实现了任意精度的浮点数运算。
3、怎么将普通的数值转换成大数值呢?
分别调用BigInteger.valueOf("普通数值"),BigDecimal.valueOf("普通数值")即可
4、BigDecimal表示:不可变的、任意精度的有符号十进制数。BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成。
BigDecimal 类提供以下操作:算术、标度操作、舍入、比较、哈希算法和格式转换。toString() 方法提供BigDecimal 的规范表示形式
5、BigDecimal的使用案例
package com.gx.commonclass;
import java.math.BigDecimal;
/**
* BigDecimal类 解决Java中浮点型的精度丢失问题,是为了更精确计算小数
* 在一些需要高精度计算的问题,比如金融里面的钱的计算,推荐使用BigDecimal public BigDecimal add(BigDecimal
* augend) public BigDecimal subtract(BigDecimal subtrahend) public BigDecimal
* multiply(BigDecimal multiplicand) public BigDecimal divide(BigDecimal
* divisor)
*/
public class BigDecimalDemo {
public static void main(String[] args) {
demo1();
demo2();
}
public static void demo1() {
BigDecimal b1 = new BigDecimal("27");
BigDecimal b2 = new BigDecimal(3);
// BigDecimal b3=BigDecimal.valueOf(15.8);
System.out.println("b1+b2=" + b1.add(b2)); // 加
System.out.println("b1-b2=" + b1.subtract(b2)); // 减
System.out.println("b1*b2=" + b1.multiply(b2)); // 乘
System.out.println("b1/b2=" + b1.divide(b2)); // 除
System.out.println("b1%b2=" + b1.remainder(b2)); // 取余
BigDecimal[] bigDecimals = b1.divideAndRemainder(b2);// 除和取余
for (BigDecimal bigDecimal : bigDecimals) {
System.out.print(bigDecimal + ",");
}
System.out.println();
System.out.println("b1^3=" + b1.pow(3));// n次方
System.out.println("|b1|=" + b1.abs());// 绝对值
System.out.println("-b1=" + b1.negate());// this*-1
System.out.println("b1取符号 " + b1.signum());// 取符号
System.out.println(b1.max(b2));
System.out.println(b1.min(b2));
// 转换成浮点型
float f1 = b1.floatValue();
double d1 = b1.doubleValue();
System.out.println(f1);
System.err.println(d1);
}
public static void demo2() {
// 浮点型的精度丢失问题
System.out.println("0.06 + 0.01 = " + (0.06 + 0.01));
System.out.println("1.0 - 0.38 = " + (1.0 - 0.33));
System.out.println("4.015 * 100 = " + (4.015 * 100));
System.out.println("1123.3 / 100 = " + (1123.3 / 100));
BigDecimal f1 = new BigDecimal("0.05");// 推荐使用
BigDecimal f2 = BigDecimal.valueOf(0.05);// 推荐使用
BigDecimal f3 = new BigDecimal(0.05);// 不推荐使用
System.out.println("f1 = " + f1);
System.out.println("f2 = " + f2);
System.out.println("f3 = " + f3);
System.out.println("使用String作为BigDecimal构造器参数:");
System.out.println("0.05 + 0.05 = " + f1.add(f2));// +
System.out.println("0.05 - 0.05 = " + f1.subtract(f2));// -
System.out.println("0.05 * 0.05 = " + f1.multiply(f2));// *
System.out.println("0.05 / 0.05 = " + f1.divide(f2));// /
System.out.println("0.05 ^ 2 = " + f1.pow(2));
System.out.println("使用double作为BigDecimal构造器参数:");
System.out.println("0.05 + 0.05 = " + f3.add(f2));
System.out.println("0.05 - 0.05 = " + f3.subtract(f2));
System.out.println("0.05 * 0.05 = " + f3.multiply(f2));
System.out.println("0.05 / 0.05 = " + f3.divide(f2));
System.out.println("0.05 ^ 2 = " + f3.pow(2));
}
}
6、BigInteger表示:不可变的任意精度的整数。所有操作中,都以二进制补码形式表示 BigInteger(如 Java 的基本整数类型)
提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。
另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、位操作以及一些其他操作
7、BigInteger的使用案例
package com.gx.commonclass;
import java.math.BigInteger;
/**
* BigInteger 任意大的整数,原则上是,只要你的计算机的内存足够大,可以有无限位的
*
*/
public class BigIntegerDemo {
public static void main(String[] args) {
BigInteger b1 = new BigInteger("100");
BigInteger b2 = new BigInteger("36");
BigInteger b3 = BigInteger.valueOf(25L);
BigInteger b4 = BigInteger.TEN; //TEN的值为10
System.out.println(b4);
System.out.println("b1+b2=" + b1.add(b2)); // +
System.out.println("b1-b2=" + b1.subtract(b2)); // -
System.out.println("b1*b2=" + b1.multiply(b2)); // *
System.out.println("b1/b2=" + b1.divide(b2)); // 除
BigInteger[] arr = b1.divideAndRemainder(b2); // 商和余数
System.out.println("b1/b2=" + arr[0]);
System.out.println("b1%b2=" + arr[1]);
System.out.println("b1%b2=" + b1.remainder(b3));// 取余
System.out.println("b1^2=" + b1.pow(2));// 2次方
System.out.println("b1和b2的最大公约数=" + b1.gcd(b2));// 公约数
System.out.println("|b1|=" + b1.abs());// 绝对值
System.out.println("-b1=" + b1.negate());// 取负数 <==>*-1
System.out.println("b1符号:" + b1.signum());// 符号函数 1 0 -1
//
b1 = BigInteger.valueOf(4);
b2 = BigInteger.valueOf(1);
System.out.println(b1.and(b2));// 且
System.out.println(b1.or(b2));// 或
System.out.println(b1.xor(b2));// 异或
System.out.println(b1.not());// 非
/**
* 如果此 BigInteger 可能为素数,则返回 true,如果它一定为合数,则返回 false。如果 certainty <=
* 0,则返回 true。
*
* 参数:
*
* certainty - 调用方允许的不确定性的度量。如果该调用返回 true,则此 BigInteger 是素数的概率超出 (1 -
* 1/2certainty)。此方法的执行时间与此参数的值是成比例的。
*
* 返回:
*
* 如果此 BigInteger 可能为素数,则返回 true,如果它一定为合数,则返回 false。
*/
System.out.println(b1.isProbablePrime(2));
System.out.println(b1.max(b2));
System.out.println(b1.min(b2));
// 转换成int 溢出
b1 = BigInteger.valueOf(100);
System.out.println(b1.pow(818));
System.out.println("===>" + b1.pow(18).intValue());
}
}
(五)、Math类
1、常用值与函数:
Math.PI 记录的圆周率
Math.E 记录e的常量
Math中还有一些类似的常量,都是一些工程数学常用量。
Math.abs 求绝对值
Math.sin 正弦函数 Math.asin 反正弦函数
Math.cos 余弦函数 Math.acos 反余弦函数
Math.tan 正切函数 Math.atan 反正切函数 Math.atan2 商的反正切函数
Math.toDegrees 弧度转化为角度 Math.toRadians 角度转化为弧度
Math.ceil 得到不小于某数的最大整数
Math.floor 得到不大于某数的最大整数
Math.IEEEremainder 求余
Math.max 求两数中最大
Math.min 求两数中最小
Math.sqrt 求开方
Math.pow 求某数的任意次方, 抛出ArithmeticException处理溢出异常
Math.exp 求e的任意次方
Math.log10 以10为底的对数
Math.log 自然对数
Math.rint 求距离某数最近的整数(可能比某数大,也可能比它小)
Math.round 同上,返回int型或者long型(上一个函数返回double型)
Math.random 返回0,1之间的一个随机数
2、主要用于数学复杂的运算(使用时查看JDK_API_1_6_zh_CN离线手册即可)
3、Math 类是一个工具类,构造器被private的,无法创建Math类的对象;Math类中的所有方法都是类方法,可以直接通过类名来调用它们。
(六)、Date、Calendar类
Date类:
1、java.util.Date中封装了时间信息(注意:一点不要引错包)
2、Date类型获取的时间时距离某一时间点(纪元1970-01-01 00:00:00)的毫秒数,来表示另一个时间点
3、常用API构造器
Date():获取当前时间点
Date(long time):time毫秒数,是一个指定的日期,距离纪元时间多少毫秒之后的日期代码:
public static void main(String[] args) {
Date now = new Date();//无参构造器,显示当前时间日期
System.out.println("当前日期:"+now);
System.out.println("毫秒数:"+now.getTime());//纪元时间距离现在的毫秒数
Date date = new Date(100000000000l);//有参构造器,距离纪元时间1000亿毫秒之后的日期
System.out.println("date:"+date);
}
方法: long getTime() 作用:获取距离纪元的毫米毫秒数
4、SimpleDateFormat【日期格式】
在java.text.SimpleDateFormat 包下,用来格式化时间的,可以将时间格式化成字符串,也可将字符串解析成时间
日期模式匹配字符
G 年代标志符
y 年
M 月
d 日
h 时 在上午或下午 (1~12)
H 时 在一天中 (0~23)
m 分
s 秒
S 毫秒
E 星期
D 一年中的第几天
F 一月中第几个星期几
w 一年中第几个星期
W 一月中第几个星期
a 上午 / 下午 标记符
k 时 在一天中 (1~24)
K 时 在上午或下午 (0~11)
z 时区
5、SimpleDateFormat()方法的使用
SimpleDateFormat()无参构造器,使用的时系统默认的时间日期格式。
SimpleDateFormat(String str)有参构造器,可以根据需要自定义时间日期格式。
代码:
public static void main(String[] args) {
Date date = new Date();
//无参构造器,显示系统默认时间日期格式
SimpleDateFormat sdf1 = new SimpleDateFormat();
//有参构造器,自定义时间日期格式
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd E ahh:mm:ss");
System.out.println(sdf1.format(date));
System.out.println(sdf2.format(date));
}
Calendar类:日历抽象类
1、常用方法
Calendar getInstance() 由于Calendar是抽象方法,只能通过向上转型的方法来实例化
void set(int field,int value) //field时间分量,value设置分量初始值(月份从0开始)
void add(int field,int value) //field时间分量,value设置分量的增加值(在当前时间日期基础上进行增加)
Date getTime() //输出时间日期
void setTime(Date date) //将日期类型设置成日历类型
getActualMaximum(int field) //获取分量中的最大/小值
2、时间分量
YEAR,MONTH,DATE,HOUR,MINUTE,SECOND DAY_OF_WEEK,DAY_OF_MONTH
案例代码:
public static void main(String[] args) {
Date date = new Date();
Calendar set = Calendar.getInstance();
Calendar add = Calendar.getInstance();
Calendar calendar = Calendar.getInstance();
set.set(Calendar.MONTH, 0);//初始月份为1月
add.add(Calendar.YEAR, 1);//第二个参数是距离现在的日期是多少天/月/年,向后加了1年
calendar.setTime(date);//date日期类型转换为Calendar类型
System.out.println("set:"+set.getTime());//输出时间
System.out.println("add:"+add.getTime());//输出时间
System.out.println("date:"+date);
}
(七)、Random类
1、Random类中实现的随机算法是伪随机,也就是有规则的随机。在进行随机时,随机算法的起源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的随机数字
2、相同种子数的Random对象,相同次数生成的随机数字是完全相同的。也就是说,两个种子数相同的Random对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。这点在生成多个随机数字时需要特别注意
3、实际案例代码:
package com.gx.commonclass;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
public class RandomDemo {
public static void main(String[] args) {
demo1();
demo2();
}
public static void demo1() {
/**
* Random类专门用于生成一个伪随机数 Random是线程安全的 “Instances of java.util.Random are
* threadsafe.”。 但是在多线程中性能比较差。
* ThreadLocalRandom类是Java7新增的一个类,它是Random的增强版。
* 在并发访问的环境下,呆证系统具有更好的线程安全性,和更好的性能。
*/
// Random random = new Random();
ThreadLocalRandom rand = ThreadLocalRandom.current();
// 生成0.0~1.0之间的伪随机的布尔值
System.out.println("rand.nextBoolean():" + rand.nextBoolean());
byte[] buffer = new byte[16];
// 生成0.0~1.0之间的伪随机的 byte
rand.nextBytes(buffer);
System.out.println(Arrays.toString(buffer));
// 生成0.0~1.0之间的伪随机double数
System.out.println("rand.nextDouble():" + rand.nextDouble());
// 生成0.0~1.0之间的伪随机float数
System.out.println("rand.nextFloat():" + rand.nextFloat());
// 生成平均值是 0.0,标准差是 1.0的伪高斯数
System.out.println("rand.nextGaussian():" + rand.nextGaussian());
// 生成一个处于int整数取值范围的伪随机整数
System.out.println("rand.nextInt():" + rand.nextInt());
// 生成0~26之间的伪随机整数
System.out.println("rand.nextInt(26):" + rand.nextInt(26));
// 生成一个处于long整数取值范围的伪随机整数
System.out.println("rand.nextLong():" + rand.nextLong());
// 10~20
System.out.println("10~20:" + (10 + rand.nextInt(10)));
}
public static void demo2() {
// 只要两个Random对象的种子相同,而且方法的调用顺序也相同,产生的随机数相同
// Random产生的数字并不是真正随机的,而是一种伪随机
Date date = new Date();
Random r1 = new Random(date.getTime());
System.out.println("第一个种子为" + date.getTime() + "的Random对象");
System.out.println("r1.nextBoolean():\t" + r1.nextBoolean());
System.out.println("r1.nextInt():\t\t" + r1.nextInt());
System.out.println("r1.nextDouble():\t" + r1.nextDouble());
System.out.println("r1.nextGaussian():\t" + r1.nextGaussian());
System.out.println("---------------------------");
Random r2 = new Random(date.getTime());
System.out.println("第二个种子为" + date.getTime() + "的Random对象");
System.out.println("r2.nextBoolean():\t" + r2.nextBoolean());
System.out.println("r2.nextInt():\t\t" + r2.nextInt());
System.out.println("r2.nextDouble():\t" + r2.nextDouble());
System.out.println("r2.nextGaussian():\t" + r2.nextGaussian());
System.out.println("---------------------------");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Date date1 = new Date();
Random r3 = new Random(date1.getTime());
System.out.println("种子为" + date1.getTime() + "的Random对象");
System.out.println("r3.nextBoolean():\t" + r3.nextBoolean());
System.out.println("r3.nextInt():\t\t" + r3.nextInt());
System.out.println("r3.nextDouble():\t" + r3.nextDouble());
System.out.println("r3.nextGaussian():\t" + r3.nextGaussian());
}
}
小结:
Java语言的内核非常小,其强大的功能主要由类库(Java API,应用程序接口)体现。从某种意义上说,掌握Java的过程也是充分利用Java类库中丰富资源的过程。
String类和StringBuffer类用来完成字符串处理,它们都具有多个构造器(构造函数)。通常使用String类来定义固定长度字符串。当字符串长度空间不确定时,应该使用StringBuffer类,它具有更丰富的功能。
公共最终类System和数学类Math中所有的变量和方法都是静态的,可以通过类名直接调用。
Java的集合类是java.util包中的重要内容。常用的有向量类Vector、堆栈类Stack、散列表类Hashtable。更多有关类库的介绍和使用方法,需要查阅Java技术文档。
二十一、反射机制
1、反射机制(Reflect)的概述:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
2、反射就是把java类中的各种成分映射成一个个的Java对象,例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象
3、反射机制的作用:反编译:.class-->.java;通过反射机制访问java对象的属性,方法,构造方法等
4、sun为我们提供了那些反射机制中的类:
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
5、具体功能实现,反射机制获取类有三种方法,我们来获取Employee类型
//第一种方式:
Classc1 = Class.forName("Employee");
//第二种方式:
//java中每个类型都有class 属性.
Classc2 = Employee.class;
//第三种方式:
//java语言中任何一个java对象都有getClass 方法
Employeee = new Employee();
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
6、创建对象:获取类以后我们来创建它的对象,利用newInstance:
Class c =Class.forName("Employee");
//创建此Class 对象所表示的类的一个新实例
Objecto = c.newInstance(); //调用了Employee的无参数构造方法.
7、获取属性:分为所有的属性和指定的属性:
方法一://获取整个类
Class c = Class.forName("java.lang.Integer");
//获取所有的属性?
Field[] fs = c.getDeclaredFields();
//定义可变长的字符串,用来存储属性
StringBuffer sb = new StringBuffer();
//通过追加的方法,将每个属性拼接到此字符串中
//最外边的public定义
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
//里边的每一个属性
for(Field field:fs){
sb.append("\t");//空格
sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
sb.append(field.getName()+";\n");//属性的名字+回车
}
sb.append("}");
System.out.println(sb);
方法二:获取特定的属性,对比着传统的方法来学习
public static void main(String[] args) throws Exception{
//以前的方式:
/*
User u = new User();
u.age = 12; //set
System.out.println(u.age); //get
*/
//获取类
Class c = Class.forName("User");
//获取id属性
Field idF = c.getDeclaredField("id");
//实例化这个类赋给o
Object o = c.newInstance();
//打破封装
idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
//给o对象的id属性赋值"110"
idF.set(o, "110"); //set
//get
System.out.println(idF.get(o));
}
(二)、加载器示例:
package com.gx.reflect;
public class ClassLoaderDemo {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader classLoader= ClassLoaderDemo.class.getClassLoader();
System.out.println(classLoader);
// 使用ClassLoader.loadClass()来加载类,不会执行初始化块
//classLoader.loadClass("com.gx.reflect.Test");
// 使用Class.forName()来加载类,默认会执行初始化块
//Class.forName("com.gx.reflect.Test");
// 使用Class.forName()来加载类,并指定ClassLoader,初始化时不执行静态块
Class.forName("com.gx.reflect.Test", false, classLoader);
}
}
class Test{
static {
System.out.println("Test 静态初始化块");
}
}
二十二、错误与异常:
(一)、在java.lang软件包中有一个java.lang.Throwable类,这个类是java中所有错误和异常的超类;顾名思义,这个类(以及子类)的实例可以通过JVM或者java的throw语句抛出。而catch子句的参数也只能是Throwable类型(或者其子类型)
(二)、Throwable类有两个子类,Error与 Exception
1、错误与异常都是在程序编译和运行时出现的错误。不同的是,异常可以被开发人员捕捉和处理;而错误一般是系统错误,一般不需要开发人员处理(也无法处理),比如内存溢出
2、Exception是java中所有异常的基类。在java中异常被分为两大类,编译时异常和运行时异常
3、编译时异常是由于外在条件不满足而引发的,比如程序视图打开一个并不存在的远程Socket端口。这种异常是可预知的。编译器强制要求对编译时异常进行捕获或声明。
4、运行时异常往往是系统错误,比如数组下标越界等。通常我们可以不做处理,系统会把它们交给缺省的异常处理程序。有人说在运行时异常出现后,异常会被一层层向上抛直到找到处理代码,如果我们没有处理运行时异常,异常会被抛到最上层然后抛出,从而导致最上层程序或线程退出。
5、Error是java中所有错误的基类。错误通常是我们无法处理的,绝大多数情况下,我们不应该试图捕获错误
(三)、实际代码较多参照目录:E:\javaStudy\20180426\src\com\gx\Exception
二十三、IO流
IO流:字符流、字节流
1、File类
File类是Java.io包下代表与平台无关的文件和目录。
可以新建文件(目录)、删除文件(目录)、重命名文件(目录),
但是不能读取文件内容。
2、流的分类
(1)按流的方向分类:输入流和输出流
输入流:只能从中读取数据,而不能向其写入数据。
输出流:只能向其写入数据,而不能从中读取数据。
(2)字符流和字节流
字节流和字符流的用法儿乎完全一样,区别在于字节流和字符流所操作的数据单元不同。
字节流操作的数据单元是8位的字节,由InputSream和OutputStream作为基类。
字符流操作的数据单元是16位的字符。由Reader和Writer作为基类。
(3)节点流和处理流
可以从/向一个特定的IO设备(如磁盘、网络)读/写数据的流,称为节点流(低级流)。
用于对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能称为处理流(高级流)
(一)、Demo1_File
抽象基类
字节输入输出(InputSiream OutputStream)
字符输入输出(Reader Writer)
1、windows与linux或者unix的路径区别
2、访问文件相关的方法 File file = new File("E:/z");
3、创建文件 File file2 = new File("E:/z/123.txt");
System.out.println(file2.createNewFile()); //创建text文本
System.out.println(file2.mkdir()); //创建文件夹
4、读写执行相关文件(在操作之前需要判断或修改文件的权限)
5、创建、修改、重命名文件(以上几点主要是输出file.什么对文件的操作)
(二)、Demo2_File
递归概念:方法定义中调用方法本身的现象,用来解决在文件夹中查找文件的问题,就是文件的嵌套隐藏
(三)、Demo03_ReaderAndWriter(字符流)
访问文件
字符输入输出(FileReader FileWriter)
实际示例:
public static void main(String[] args) throws IOException {
//先在对应文件创建一个代字符串的文本
Reader reader = new FileReader("E:\\z\\123.txt");
String str = "";
char[] cbuf = new char[1024000]; // 每行输出多少个字符或者全部输出
int count = 0;
while (-1 != (count = reader.read(cbuf, 0, cbuf.length))) {
System.out.println(cbuf); // 输出文本里面的字符
str = str + String.valueOf(cbuf, 0, count); //获取字符串个数
}
//用完流,要记得关闭流
reader.close();
System.out.println(str.length()); //输出流
//方法一:将以上文本内容写入新建的文本中去
Writer writer = new FileWriter("E:\\z\\1234.txt");
char[] cbuf1 =str.toCharArray();
writer.write(cbuf1, 0, cbuf1.length);
writer.close(); //关闭流
//方法二 正确处理方式(边读边写入文本中)
Reader reader2 =new FileReader("E:\\z\\123.txt");
Writer writer2 =new FileWriter("E:\\z\\1232.txt");
char[] cbuf2 =new char[102400];
int count2 =0;
while(-1 !=(count2 =reader2.read(cbuf2,0,cbuf2.length))){
writer2.write(cbuf2,0,count2);
}
reader.close();
writer2.close();
}
(四)、Demo04_InputStreamAndOutputStream(字节流)
访问文件
字节输入输出(FileInputStream FileOutputStream)
实际示例:
public static void main(String[] args) throws IOException {
//查找文件内容
File file=new File("E:\\z\\123.avi");
//读文件流
InputStream is=new FileInputStream(file);
//写文件流
OutputStream ou=new FileOutputStream("E:\\z\\1234.mp4");
//判断输出
byte[] buf=new byte[10240];
int count=0;
while(-1!=(count=is.read(buf, 0, buf.length))){
ou.write(buf,0,count);
}
//关闭流
is.close();
ou.close();
}
(五)、另外一种处理流方式
实际示例:
package com.gx.iodemo;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
/*
* 处理流可以隐藏底层设备上节点流的差异,并对外提供更加方便的输入/ 输出方法,让程序员只需关心高级流的操作。
* 使用处理流时的典型思路是,使用处理流来包装节点流,程序通过处理流来执行输入/输出功能, 让节点流与底层的I/O设备、文件交互。
* 处理流和节点流的区别,只要流的构造器存在参数不是一个物理节点,而是己经存在的流,那么这种流就一定是处理流;
* 而所有节点流都是直接以物理IO节点作为构造器参数的。
*/
public class Demo05_PrintStream {
public static void main(String[] args) throws IOException {
demo1();
demo2();
}
public static void demo1() throws IOException {
Writer writer = new FileWriter("E:\\z\\abcd.txt");
String str = "sdfghjk0sdd\n";
String str2 = "sdfghjk0sdd\n";
String str3 = "sfqadafgrwd\n";
// 写入文本并关闭流
writer.write(str);
writer.write(str2);
writer.write(str3);
writer.close();
}
public static void demo2() throws IOException {
PrintWriter printWriter = new PrintWriter("E:\\z\\abcd123.txt");
String str = "sdfghjk0sdd";
String str2 = "sdfghjk0sdd";
String str3 = "sdfghjk0sdd";
printWriter.println(str);
printWriter.println(str2);
printWriter.println(str3);
//在使用处理流包装了底层节点流之后,关闭输入/输出流资源时,只要关闭最上层的处理流即可
//关闭最上层的处理流时,系统会自动关闭被该处理流包装的节点流
printWriter.close();
}
}
(六)、Demo06_ArrayStream(数组)
访问数组
字节的输入输出(ByteArrayInputStream ByteArrayOutputStream)
字符的输入输出(CharArrayReader CharArrayWriter)
实际案例:
package com.gx.iodemo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayReader;
import java.io.CharArrayWriter;
import java.io.IOException;
public class Demo06_ArrayStream {
public static void main(String[] args) throws IOException {
demo1();
demo2();
}
//数组字符输入输出
public static void demo1() throws IOException {
// 定义字符类型字符串
char[] cs = "qmsfkdmkmvckmxaDSFDSSD2s156d156fc6we2fr31".toCharArray();
CharArrayReader reader = new CharArrayReader(cs);
CharArrayWriter writer = new CharArrayWriter();
char[] buf = new char[10];
int count = 0;
while (-1 != (count = reader.read(buf, 0, buf.length))) {
System.out.println(buf);
writer.write(buf, 0, count);
}
char[] newChars = writer.toCharArray();
System.out.println(newChars);
reader.close();
writer.close();
}
//数组字节输入输出
public static void demo2() throws IOException {
//定义字节字符串
byte[] cs = "qmsfkdmkmvckmxaDSFDSSD2s156d156fc6we2fr31".getBytes();
ByteArrayInputStream input = new ByteArrayInputStream(cs);
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buf = new byte[10];
int count = 0;
while (-1 != (count = input.read(buf, 0, buf.length))) {
System.out.println(buf);
output.write(buf, 0, count);
}
byte[] newBytes = output.toByteArray();
System.out.println(new String(newBytes));
input.close();
output.close();
}
}
(七)、Demo07_PipedStream(管道)
管道访问
管道字节输入输出(PipedInputStream PipedOutputStream)
管道字符输入输出(PipedReader PipedWriter)
管道流包括四个类PipedOutputStream/PipedWriter和PipedInputStream/PipedReader
其中PipedOutputStream/PipedWriter是写入者/生产者/发送者;PipedInputStream/PipedReader是读取者/消费者/接收者
注意:运用到多线程的时候才使用到
(八)、Demo08_StringReaderAndStringWriter(字符串)
访问字符串
字符串字符输入输出(StringReader StringWriler)
实际示例:
public static void main(String[] args) throws IOException {
//初始化string类型
String string ="asdyogfo71kar7015610hrhyoqy150yyfaofyq075ll0[-9]";
StringReader reader =new StringReader(string);
StringWriter writer =new StringWriter();
char[] cbuf=new char[100];
int count=0;
while(-1!=(count=reader.read(cbuf, 0, cbuf.length))){
System.out.println(cbuf);
writer.write(cbuf, 0, count);
}
String str=writer.toString(); //格式转换
System.out.println(str); //输出
//关闭流
reader.close();
writer.close();
}
(九)、Demo09_BufferedReader(缓冲流)
缓冲字节输入输出(BufferedInputStrcam BufferedOutputStream) 很少用
缓冲字符输入输出(BufferedReader BufferedWriter) 多用
public static void main(String[] args) {
//BufferedReader 带缓冲的功能,可以一次读取一行(以换行符为结束标志)
//注意:低于6.0版本的不建议用try catch
try (Reader reader = new FileReader(new File("E:\\z\\asdg.txt"));
BufferedReader bufferedReader = new BufferedReader(reader);) {
String str = "";
while (null != (str = bufferedReader.readLine())) {
System.out.println(str);
}
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
(十)、Demo10_InputStreamToInputStreamReader(转换流)
转换字符输入输出(InputStreamReader OutputStreamWriter)
实际示例:
public static void main(String[] args) throws IOException {
//转换流的字符输入
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader bufferedReader = new BufferedReader(reader);
String str = "";
while (null != (str = bufferedReader.readLine())) {
System.out.println(str);
if (str.equals("exit")) {
break;
}
}
bufferedReader.close();
//转换字符的输出
OutputStream out = new FileOutputStream("E:\\z\\1314.txt");
OutputStreamWriter writer = new OutputStreamWriter(out);
writer.write("qwryoryogflafphclzb");
writer.close();
}
(十一)、Demo11_Pushback(推回输入流)
推回字符输入流(PushbackReader)
1、PushbackReader实际案例:读取一个文件中指定某一个区域
public static void main(String[] args) throws IOException {
PushbackReader reader =new PushbackReader(
new FileReader("E:\\javaStudy\\20180426\\src\\com\\gx\\iodemo\\Demo07_PipedStream.java"),
64);
char[] cs =new char[32]; //读取缓冲区
int count =0;
int targetIndex = 0; //行索引
String strLast = "";// 记录上次读取的字符串
while (-1 != (count = reader.read(cs, 0, cs.length))) {
String str = new String(cs, 0, count);
String strCount = strLast + str;
if ((targetIndex = strCount.indexOf("new PipedOutputStream")) > -1) {
// 将本次内容和上次内容一起推回缓冲区
// *****推回缓冲区的内容大小不能超过缓冲区的大小
reader.unread(strCount.toCharArray());
// 重新定义一个长度为targetIndex的char数组
if (targetIndex > 32) {
cs = new char[targetIndex];
}
// 再次读取指定长度的内容(就是目标字符串之前的内容)
reader.read(cs, 0, targetIndex);
str = new String(cs, 0, targetIndex);
System.out.println(str);
break;
} else {
System.out.println(strLast);
strLast = str;
}
}
}
(十二)、Demo12_RandomAccessFile(功能最丰富的文件内容访问类,支持随机访问)
详细内容看实际示例:
package com.gx.iodemo;
/*
* RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,
* 它提供了众多的方法 来访问文件内容,它既可以读取文件内容,也可以向文件输出数据。
* RandomAccessFile支持“随机访问”的方式,程序可以直接跳转到文件的任意地方来读写数据
* > long getHlePointerO:返回文件记录指针的当前位置。
* > void seek(long pos):将文件记录指针定位到pos位置。
*
* >"r":以只读方式打开指定文件。如果试图对该RandomAccessFile执行写入方法,都将抛出 IOException 异常。
* >"rw":以读、写方式打开指定文件。如果该文件尚不存在,则尝试创建该文件。
* >"rws”:以读、写方式打开指定文件。相对于"rw"模式,还要求对文件的内容或元数据的每个更 新都同步写入到底层存储设备。
* >"rwd": 以读、写方式打开指定文件。相对于"rw"模式,还要求对文件的内容的每个更新都同步写入到底层存储设备。
*
* 元数据是文件的附加属性,如文件大小、创建时间、所有者等信息
*
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
public class Demo12_RandomAccessFile {
public static void main(String[] args) throws IOException {
// demo1();
// demo2();
// demo3();
demo4();
}
// "r"以只读方式打开指定文件
public static void demo1() throws IOException {
RandomAccessFile accessFile = new RandomAccessFile("E:\\z\\r123.txt",
"r"); // 只读
accessFile.seek(51); // 调到指定位置
// 读取文件
byte[] bytes = new byte[1024];
int count = 0;
while (-1 != (count = accessFile.read(bytes, 0, bytes.length))) {
System.out.println(new String(bytes, 0, count, "gbk"));
}
accessFile.close();
}
// "rw"以读、写方式打开指定文件
public static void demo2() throws IOException {
RandomAccessFile accessFile = new RandomAccessFile("E:\\z\\rw123.txt",
"rw");
accessFile.seek(accessFile.length()); // 调到最后位置
accessFile.write("============".getBytes("gbk")); // 在文件最后追加
accessFile.close();
}
// "rw"以读、写方式打开指定文件
public static void demo3() throws IOException {
/**
* RandomAccessFile依然不能向文件的指定位置插入内容,如果直接将文件记录指针移动到中间某位置后开始输出,
* 则新输出的内容会覆盖文件中原有的内容。如果需要向指定位置插入内容, 程序需要先把插入点后面的内容读入缓冲区,等把需要插入的数据写入文
* 件后,再将缓冲区的内容追加到文件后面。
*/
RandomAccessFile accessFile = new RandomAccessFile("E:\\z\\rw123.txt",
"rw");
accessFile.seek(51); // 调到指定位置
accessFile.write("=============".getBytes("gbk"));
accessFile.close();
}
// "rw"以读、写方式打开指定文件
public static void demo4() throws IOException {
File tmp = File.createTempFile("tmp", null);
tmp.deleteOnExit();
FileOutputStream tmpOutputStream = new FileOutputStream(tmp);
FileInputStream tmpFileInputStream = new FileInputStream(tmp);
RandomAccessFile accessFile = new RandomAccessFile("E:\\z\\rw122.txt",
"rw");
accessFile.seek(51);
byte[] bytes = new byte[1024];
int count = 0;
while (-1 != (count = accessFile.read(bytes, 0, bytes.length))) {
tmpOutputStream.write(bytes, 0, count);
}
accessFile.seek(51); // 调到指定位置
accessFile.write("===========".getBytes("gbk")); // 插入想插入的内容
// 读取会临时文件里面的内容,追加会源文件
while (-1 != (count = tmpFileInputStream.read(bytes, 0, bytes.length))) {
accessFile.write(bytes, 0, count);
}
// 关闭流
tmpFileInputStream.close();
tmpOutputStream.close();
accessFile.close();
}
}
(十三)、Demo13_ObjectStream(对象流)
对象字节输入输出流(ObjectInputStream ObjectOutputStream)
实际示例:
package com.gx.iodemo;
/*
* 序列化机制允许将实现序列化的Java对象转换成字节序列,这些字节序列可以保存在磁盘上,或 通过网络传输,以备以后重新恢复成原来的对象。
* 序列化机制使得对象可以脱离程序的运行而独立存在。 对象的序列化(Serialize)指将一个Java对象写入IO流中, 对象的反序列化
* (Deserialize)则指从IO流中恢复该Java对象。
*
* 序列化接口有:Serializable(常用) 和 Externalizable(可以先不管) se ee me
* 序列化机制是JavaEE平台的基础。通常建议:程序创建的每个JavaBean类都实现Serializable接口。
*/
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Demo13_ObjectStream {
public static void main(String[] args) throws Exception {
demo1();
demo2();
}
//字节输出
public static void demo1() throws IOException {
Person person =new Person("小明",20);
FileOutputStream out =new FileOutputStream("E:\\z\\person.txt");
ObjectOutputStream outputStream =new ObjectOutputStream(out);
// 周用ObjectOutputStream对象的writeObject()方法输出可序列化对象
outputStream.writeObject(person);
outputStream.close();
}
//字节输入
public static void demo2() throws Exception{
FileInputStream in = new FileInputStream("E:\\z\\person1.txt");
ObjectInputStream inputStream = new ObjectInputStream(in);
/**
* 必须指出的是,反序列化读取的仅仅是Java对象的数据,而不是Java类, 因此采用反序列化恢复
* Java对象时,必须提供该Java对象所属类的class文件, 否则将会引发ClassNotFoundException异常。
* 反序列化无须通过构造器来初始化Java对象。
*/
com.gx.iodemo1.Person person =(com.gx.iodemo1.Person)inputStream.readObject();
System.out.println(person.getName());
}
}
class Person implements Serializable{
private static final long serialVersionUID = -3138823756540735938L;
private String name;
private int age;
private int height;
public Person(){
System.out.println("无参构造器");
}
public Person(String name,int age){
this.name=name;
this.age=age;
System.out.println("有参构造器");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
class Person1 implements Serializable{
private static final long serialVersionUID = -3138823756540735938L;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
输入时调用的方法
package com.gx.iodemo1;
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = -876496174346793087L;
private String name;
private int age;
private int height;
public Person() {
System.out.println("无参构造器");
}
public Person(String name,int age){
this.name=name;
this.age=age;
System.out.println("有参构造器");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
二十四、JavaMySQL
1、参考文档步骤安装MySQL lnstaller接着破解SQLyogEnt之后使用
2、打开SQLyogEnt新建,主机地址默认,常见用户名及密码,注意端口号3306之后连接
3、右键创建数据库,填写数据库名、数据库字符集选择utf8、数据库校队规则选择utf_general_ci即可创建
4、在tales里建表,大致建表格式数SQLserver大同小异
5、分页(limit 1,5) 加参数表示:从哪查,要查多少条
6、mysql-connector-java-5.1.22-bin.jar(java驱动包)
- 引用架包步骤:在myeclipse对应的项目中右键选择properties接着选择Java Build Path之后选择Libraries再选择右边的Add External....之后选择文件添加以上java驱动包,最后项目文件下面显示该架包即可
二十五、部分代码封装及调用
步骤:
1、先将jbdc.properties加入到src中来
#生产环境使用
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/domedb?useUnicode=true&characterEncoding=utf8
username=root
password=1234
2、把需要及重复使用的代码打包进行封装
实例代码:
package com.gx.jdbcdemo;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class DBUtil {
private static String driver="";
private static String url="";
private static String username="";
private static String password="";
static{
Properties properties=new Properties();
try {
properties.load(new FileReader("src//jdbc.properties"));
driver=properties.getProperty("driver");
url=properties.getProperty("url");
username=properties.getProperty("username");
password=properties.getProperty("password");
Class.forName(driver);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(url, username, password);
}
public static void close(Connection conn,PreparedStatement ps,ResultSet rs) {
try {
if (conn!=null) {
conn.close();
}
if (ps!=null) {
ps.close();
}
if (rs!=null) {
rs.close();
}
} catch (SQLException e2) {
// TODO: handle exception
}
}
}
3、再编写个查询测试方法进行验证封装好的代码是否可以使用
实例代码:
package com.gx.jdbcdemo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class SelectDemo {
public static void main(String[] args) {
Connection conn =null;
PreparedStatement ps =null;
ResultSet rs =null;
try {
conn=DBUtil.getConnection();
String sql = "select * from urse";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
System.out.println("id:" + rs.getInt(1) + " name:"
+ rs.getString(2) + " pass:" + rs.getString(3));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
DBUtil.close(conn, ps, rs);
}
}
}
二十六、悲观锁与乐观锁
1、悲观锁实际案例:
package com.gx.jdbcdemo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/*
* 悲观锁:即很悲观,每次拿数据的时候都觉得数据会被人更改,所以拿数据的时候就把这条记录锁掉,这样别人就没法改这条数据了,一直到你的锁释放
* 悲观锁的实现采用的数据库内部的锁机制 for update
* 在查询数据的时候先用for update把这条数据锁住,然后更改完这条数据再提交。这样别的线程没法更新这条数据,也就保证了不会丢失更新
*/
public class DemoLock1 {
public static void main(String[] args) {
//定义全局变量
Connection conn =null;
PreparedStatement ps =null;
ResultSet rs =null;
try {
//加载jar及连接数据库
conn=DBUtil.getConnection();
//设置自动提交为false
conn.setAutoCommit(false);
//根据条件查询数据并限制锁
String sql ="select * from urse where id =4 for update";
ps=conn.prepareStatement(sql);
//获取返回信息
rs =ps.executeQuery();
while(rs.next()){
//输出结果
System.out.println("id:" + rs.getInt(1) + " name:"
+ rs.getString(2) + " pass:" + rs.getString(3));
//根据id进行修改
sql="update urse set name='abc' where id=4";
ps=conn.prepareStatement(sql);
ps.executeUpdate();
}
conn.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
DBUtil.close(conn, ps, rs);
}
}
}
2、乐观锁实际案例:
package com.gx.jdbcdemo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/*
* 乐观锁:
* 查询数据的时候总觉得不会有人更改数据,等到更新的时候再判断这个数据有没有被人更改,有人更改了则本次更新失败
* 通过在表里面加一个版本号的形式字段(version)
*/
public class DemoLock2 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn =DBUtil.getConnection();
conn.setAutoCommit(false);
String sql = "select * from urse where id = 4";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
//需要在数据库加一个字段version(记录数据的版本)
int version=rs.getInt("version");
sql = "update urse set name='abc',version=version+1 where id =4 and version=?";
ps = conn.prepareStatement(sql);
ps.setInt(1, version);
System.out.println(ps.executeUpdate());
}
conn.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, rs);
}
}
}
二十七、Mysql的引擎
Mysql的引擎
mysql-5.5.5开始,InnoDB 作为默认存储引擎,以前是MyISAM引擎
MyISAM引擎和InnoDB引擎的比较:
MyISAM 是非事务安全型的,而 InnoDB 是事务安全型的。
MyISAM 锁的粒度是表级,而 InnoDB 支持行级锁定。
MyISAM 支持全文类型索引,而 InnoDB 不支持全文索引。
MyISAM 相对简单,所以在效率上要优于 InnoDB,小型应用可以考虑使用 MyISAM。
MyISAM 表是保存成文件的形式,在跨平台的数据转移中使用 MyISAM 存储会省去不少的麻烦。
InnoDB 表比 MyISAM 表更安全,可以在保证数据不会丢失的情况下,切换非事务表到事务表(alter table tablename type=innodb)。
default-storage-engine=InnoDB
default-storage-engine=MYISAM
下面逐次介绍一下各种引擎:
ISAM
该引擎在读取数据方面速度很快,而且不占用大量的内存和存储资源;但是ISAM不支持事务处理、不支持外来键、不能够容错、也不支持索引。该引擎在包括MySQL 5.1及其以上版本的数据库中不再支持。
MyISAM
该引擎基于ISAM数据库引擎,除了提供ISAM里所没有的索引和字段管理等大量功能,MyISAM还使用一种表格锁定的机制来优化多个并发的读写操作,但是需要经常运行OPTIMIZE TABLE命令,来恢复被更新机制所浪费的空间,否则碎片也会随之增加,最终影响数据访问性能。MyISAM还有一些有用的扩展,例如用来修复数据库文件的MyISAMChk工具和用来恢复浪费空间的 MyISAMPack工具。MyISAM强调了快速读取操作,主要用于高负载的select,这可能也是MySQL深受Web开发的主要原因:在Web开发中进行的大量数据操作都是读取操作,所以大多数虚拟主机提供商和Internet平台提供商(Internet Presence Provider,IPP)只允许使用MyISAM格式。
MyISAM类型的表支持三种不同的存储结构:静态型、动态型、压缩型。
静态型:指定义的表列的大小是固定(即不含有:xblob、xtext、varchar等长度可变的数据类型),这样MySQL就会自动使用静态MyISAM格式。使用静态格式的表的性能比较高,因为在维护和访问以预定格式存储数据时需要的开销很低;但这种高性能是以空间为代价换来的,因为在定义的时候是固定的,所以不管列中的值有多大,都会以最大值为准,占据了整个空间。
动态型:如果列(即使只有一列)定义为动态的(xblob, xtext, varchar等数据类型),这时MyISAM就自动使用动态型,虽然动态型的表占用了比静态型表较少的空间,但带来了性能的降低,因为如果某个字段的内容发生改变则其位置很可能需要移动,这样就会导致碎片的产生,随着数据变化的增多,碎片也随之增加,数据访问性能会随之降低。
对于因碎片增加而降低数据访问性这个问题,有两种解决办法:
a、尽可能使用静态数据类型;
b、经常使用optimize table table_name语句整理表的碎片,恢复由于表数据的更新和删除导致的空间丢失。如果存储引擎不支持 optimize table table_name则可以转储并 重新加载数据,这样也可以减少碎片;
压缩型:如果在数据库中创建在整个生命周期内只读的表,则应该使用MyISAM的压缩型表来减少空间的占用。
HEAP(也称为MEMORY)
该存储引擎通过在内存中创建临时表来存储数据。每个基于该存储引擎的表实际对应一个磁盘文件,该文件的文件名和表名是相同的,类型为.frm。该磁盘文件只存储表的结构,而其数据存储在内存中,所以使用该种引擎的表拥有极高的插入、更新和查询效率。这种存储引擎默认使用哈希(HASH)索引,其速度比使用B-+Tree型要快,但也可以使用B树型索引。由于这种存储引擎所存储的数据保存在内存中,所以其保存的数据具有不稳定性,比如如果mysqld进程发生异常、重启或计算机关机等等都会造成这些数据的消失,所以这种存储引擎中的表的生命周期很短,一般只使用一次。
CSV(Comma-Separated Values逗号分隔值)
使用该引擎的MySQL数据库表会在MySQL安装目录data文件夹中的和该表所在数据库名相同的目录中生成一个.CSV文件(所以,它可以将CSV类型的文件当做表进行处理),这种文件是一种普通文本文件,每个数据行占用一个文本行。该种类型的存储引擎不支持索引,即使用该种类型的表没有主键列;另外也不允许表中的字段为null。
BLACKHOLE(黑洞引擎)
该存储引擎支持事务,而且支持mvcc的行级锁,写入这种引擎表中的任何数据都会消失,主要用于做日志记录或同步归档的中继存储,这个存储引擎除非有特别目的,否则不适合使用。详见博客《BlackHole 存储引擎》
ARCHIVE
该存储引擎非常适合存储大量独立的、作为历史记录的数据。区别于InnoDB和MyISAM这两种引擎,ARCHIVE提供了压缩功能,拥有高效的插入速度,但是这种引擎不支持索引,所以查询性能较差一些。
PERFORMANCE_SCHEMA
该引擎主要用于收集数据库服务器性能参数。这种引擎提供以下功能:提供进程等待的详细信息,包括锁、互斥变量、文件信息;保存历史的事件汇总信息,为提供MySQL服务器性能做出详细的判断;对于新增和删除监控事件点都非常容易,并可以随意改变mysql服务器的监控周期,例如(CYCLE、MICROSECOND)。
InnoDB
该存储引擎为MySQL表提供了ACID事务支持、系统崩溃修复能力和多版本并发控制(即MVCC Multi-Version Concurrency Control)的行级锁;该引擎支持自增长列(auto_increment),自增长列的值不能为空,如果在使用的时候为空则自动从现有值开始增值,如果有但是比现在的还大,则直接保存这个值; 该引擎存储引擎支持外键(foreign key) ,外键所在的表称为子表而所依赖的表称为父表。该引擎在5.5后的MySQL数据库中为默认存储引擎。
Berkeley(BDB)
该存储引擎支持COMMIT和ROLLBACK等其他事务特性。该引擎在包括MySQL 5.1及其以上版本的数据库中不再支持。
Merge
该引擎将一定数量的MyISAM表联合而成一个整体。参见博客《MySQL Merge存储引擎》
Federated
该存储引擎可以不同的Mysql服务器联合起来,逻辑上组成一个完整的数据库。这种存储引擎非常适合数据库分布式应用。
Cluster/NDB
该存储引擎用于多台数据机器联合提供服务以提高整体性能和安全性。适合数据量大、安全和性能要求高的场景。
二十八、新建 web Project
新建 web Project
com
|-gx
|-servlet/web/controller 放 servlet
|-service 放服务层的接口
| |-impl 服务接口的实现类
|-dao 数据库操作接口
| |-impl 数据库操作接口的实现类
|-po 数据的实体类
|-vo
|-common 放公共的类
|-filter 过滤器
|-util 放工具类
二十九、Tomcat的使用
1、E:\Tomcat\apache-tomcat-7.0.52\bin里面的shutdown和startup
2、conf里面的server.xml打开将中文问题:URIEncoding="UTF-8"放到对应位置
Tomcat
Tomcat 是 Apache 软件基金会一个项目,由 Apache、Sun 和部分公司和个人一起开发完善的轻量级 Web 应用服务器,是 Servlet 规范和 JSP 规范的开源实现。是免费开源的。
tomcat的配置和启动
1、配置文件:server.xml
端口:默认8080
中文问题:URIEncoding="UTF-8"
2、启动tomcat:startup.bat
Myeclipse配置tomcat7
myeclipse > Servers > Tomcat >Tomcat 7.x
web.xml项目配置文件
修改冲突快捷键:ctrl+shift+o
三十、JSP
1、Jsp是一种建立在Servlet规范提供的功能之上的动态网页技术,允许在网页文件中嵌入java代码和jsp标记。
Java 服务器页面 (Java Server Page ,JSP) ;扩展名 .jsp
2、jsp的执行过程
(1)Jsp文件在用户第一次请求时,会被编译成Servlet,然后由这个Servlet处理用户的请求,所以jsp可以看成是运行时的Servlet
(2)Jsp容器(也就是Servlet容器)管理jsp页面声明周期分为两个阶段.即转换阶段和执行阶段
(3)当有一个对jsp页面的请求到来时,jsp容器检查jsp页面的语法是否正确,将jsp页面转换为Servlet源文件,然后调用javac命令编译Servlet源文件生成字节码文件.这是转换阶段
(4)Servlet容器加载转换后的Servlet类,这是执行阶段
3、JSP 页面的元素
静态内容 ------------→ HTML、js、css静态文本
指令 ------------→ 以 <%@ 开始,以 %> 结束
表达式 ------------→ <%=Java表达式 %> *
代码块 ------------→ <% Java 代码(变量:_jspService方法的局部变量) %> *
声明 ------------→ <%! 函数或方法、变量(成员变量) %> *
动作 ------------→以 <jsp: 动作名 开始,以 </jsp:动作名> 结束
注释 ------------→<!-- 这是注释,但客户端可以查看到 --> <%-- 这也是注释,但客户端不能查看到 --%> *
4、JSP 指令 用来设置与整个 JSP 页面相关的属性。
<%@ page ... %> 定义页面的依赖属性,比如脚本语言、error 页面、缓存需求等等
<%@ include ... %> 包含其他文件
<%@ taglib ... %> 引入标签库的定义,可以是自定义标签
5、jsp的九大内置对象
request HttpServletRequest 类的实例
response HttpServletResponse 类的实例
out PrintWriter 类的实例,用于把结果输出至网页上
session HttpSession 类的实例
application ServletContext 类的实例,与应用上下文有关
config ServletConfig 类的实例
pageContext PageContext 类的实例,提供对 JSP 页面所有对象以及命名空间的访问
page 类似于 Java 类中的 this 关键字
Exception Exception 类的对象,代表发生错误的 JSP 页面中对应的异常对象
JSP 作用域包括 page、request、session 和 application
6、 EL表达式
EL 为表达式语言(Expression Language),可以简化对变量的对象的访问
语法 :${EL Expression}所有的表达式以”${”开始,以”}”结束。
是否启用EL表达式 isELIgnored ="true|false"
JSP EL 表达式用于以下情形
静态文本
标准标签和自定义标签
EL不能在脚本元素中使用 脚本元素不是指JavaScript脚本,而是 <% Java 代码 %>
JavaScript脚本在jsp中属于静态内容
EL使用”[ ]”和”.”操作符来访问数据
对于连字符(-)或者其它特殊字符的字符串只能用“[ ]”操作符,而不能用“.”操作符,这也是“[ ]”和“.”操作符的区别 如 ${header["User-Agent"]}
EL表达式的操作内容可以是:常量、变量、jsp隐含对像
EL表达式还提供了对操作内容的运算:属性取值、运算、逻辑运算
EL表达式的操作结果会自动输出到输出流对像中
EL 表达式只能通过内置对象取值,也就是只读操作
EL 运算符
(1)、EL 算术运算符 + - * /(div) %(mod)
(2)、EL 关系运算符 ==(eq) !=(ne) <(lt) <=(le) >(gt) >=(ge)
(3)、EL 逻辑运算符 &&(and) ||(or) !(not)
(4)、EL 其他运算符
1) empty 运算符 用来判断值是否为null 或空的
2) 条件运算符 ${ A ? B : C}意思是说,当A 为true 时,执行B;而A 为false 时,则执行C
3) ( ) 括号运算符 用来改变执行优先权,例如:${ A * (B+C) }
隐含对象 类型 说明
PageContext javax.servlet.ServletContext 表示此 JSP 的 PageContext
PageScope java.util.Map 取得 Page 范围的属性名称所对应的值
RequestScope java.util.Map 取得 Request 范围的属性名称所对应的值
sessionScope java.util.Map 取得 Session 范围的属性名称所对应的值
applicationScope java.util.Map 取得 Application 范围的属性名称所对应的值
param java.util.Map 如同 ServletRequest.getParameter(String name)。回传 String 类型的值
paramValues java.util.Map 如同 ServletRequest.getParameterValues(String name)。回传 String[] 类型的值
header java.util.Map 如同 ServletRequest.getHeader(String name)。回传 String 类型的值
headerValues java.util.Map 如同 ServletRequest.getHeaders(String name)。回传 String[] 类型的值
cookie java.util.Map 如同 HttpServletRequest.getCookies()
initParam java.util.Map 如同 ServletContext.getInitParameter(String name)。回传 String 类型的值
el表达式的作用域 PageScope RequestScope sessionScope applicationScope
域对象的操作各自属性的方法:
getAttribute(String name):获取一个name属性的值
getAttributeNames():获取所有属性的name
setAttribute(String name ,Object obj):为name属性设置一个obj的值
removeAttribute(String name):移除name属性
在index.jsp中的路径
<meta http-equiv="refresh" content="0;url=<%=path%>/servlet/ToLoginServlet">
7、JSP文件必须在JSP服务器内运行。
(1)JSP文件必须生成Servlet才能执行。
(2) 每个JSP页面的第一个访问者速度很慢,因为必须等待JSP编译成Servlet。
(3) JSP页面的访问者无须安装任何客户端,甚至不需要可以运行Java的运行环境,因为JSP页面输送到客户端的是标准HTML页面。
(4) JSP页面的静态内容、JSP脚本都会转换成Servlet的xxxService()方法,类似于自行创建Servlet时service()方法。
(5) JSP声明部分,转换成Servlet的成员部分。所有JSP声明部分可以使用private,protected,public,static等修饰符,其他地方则不行。
(6)P的输出表达式(<%= ..%>部分),输出表达式会转换成Servlet的xxxService()方法里的输出语句。
(7) 九个内置对象要么是xxxService()方法的形参,要么是该方法的局部变量,所以九个内置对象只能在JSP脚本和输出表达式中使用
<%! %>里声明的变量和方法都是作为类的属性和方法存在的,而<% %>里声明的变量则是作为_jspService这个方法的内部属性 (这也决定了<% %>里不能声明方法)
8、JSP基本概念:
JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。JSP技术有点类似ASP技术,它是在传统的网页HTML(标准通用标记语言的子集)文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。 用JSP开发的Web应用是跨平台的,既能在Linux下运行,也能在其他操作系统上运行。
它实现了Html语法中的java扩展(以 <%, %>形式)。JSP与Servlet一样,是在服务器端执行的。通常返回给客户端的就是一个HTML文本,因此客户端只要有浏览器就能浏览。
JSP技术使用Java编程语言编写类XML的tags和scriptlets,来封装产生动态网页的处理逻辑。网页还能通过tags和scriptlets访问存在于服务端的资源的应用逻辑。JSP将网页逻辑与网页设计的显示分离,支持可重用的基于组件的设计,使基于Web的应用程序的开发变得迅速和容易。 JSP(JavaServer Pages)是一种动态页面技术,它的主要目的是将表示逻辑从Servlet中分离出来。
Java Servlet是JSP的技术基础,而且大型的Web应用程序的开发需要Java Servlet和JSP配合才能完成。JSP具备了Java技术的简单易用,完全的面向对象,具有平台无关性且安全可靠,主要面向因特网的所有特点
三十一、标签库:
视频课程讲解(代码目录:E:\javaStudy\20180922)
(1)先在index.jsp中配置<meta http-equiv="refresh" content="0;url=<%=path%>/servlet/demoServlet">
(2)demo1主要讲解:核心标签库,要用到JSTL中的core和I18N两个URL
URL:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
(3)demo2主要讲解:I18N 国际化(少用,知道就好)
要新建一个文件装语言代码如(applicationMessage_zh_CN.properties)
(4)demo3主要讲解:<fmt:formatDate>与<fmt:formatNumber>的属性和pattern
JSP 标准标签库
1、Java Server Pages 标准标签库 (JSTL) 包含的各种标签可用于 JSP 页面中
2、JSTL 的优点:
提供一组标准标签
可用于编写各种动态 JSP 页面
用于访问数据库、有条件地执行代码和支持国际化
3、JSTL的组成:
功能范围 URI 前缀
core(核心) http://java.sun.com/jsp/jstl/core c *
I18N http://java.sun.com/jsp/jstl/fmt fmt *
SQL http://java.sun.com/jsp/jstl/sql sql
XML http://java.sun.com/jsp/jstl/xml x
funcions http://java.sun.com/jsp/jstl/functions fn *
4、核心标签库
|----通用标签
| |----set <c:set>用于在某个范围(Request,Session,Application等)中设置某个值,或者设置某个对象的属性
| |----remove <c:remove>用于删除某个变量或者属性
| |----out <c:out>计算一个表达式并将结果输出到当前的JspWrite对象。
| |----catch <c:catch>将可能抛出异常的代码放置在<c:catch>和</c:catch>之间,如果其中的代码抛出异常,异常将被捕获
|
|----条件标签
| |----if <c:if>实现java语言中if语句的功能
| |----choose <c:choose>、<c:when>、<c:otherwise>一起实现互斥条件的执行,类似于java语言的if/else语句
| |----when
| |----otherwise
|
|-----迭代标签
|----forEach <c:forEach>对于包含了多个对象的集合进行迭代,重复执行它的标签体,或者重复迭代固定的次数
|----forTokens <c:forTokens>用于迭代字符串中由分隔符的各个成员
5、I18N 国际化
程序在不做任何修改的情况下,就可以在不同的地区和不同的语言环境下,按照当地的语言和格式习惯显示字符.
I18N与格式化标签
|----setLocale <fmt:setLocale>用于设置用户的本地语言环境,并将指定的Locale保存到javax.servlet.jsp.jstl.fmt.locale配置变量中去
|----bundle
|----setBundle <fmt:setBudle>创建一个I18N本地上下文环境,加载资源包到上下文中,资源包的名字通过basename指定.
|----message <fmt:message>从资源包中查找一个指定键的值,用于显示本地化的消息
|----formatDate <fmt:formatDate>标签用于格式化日期
|----formatNumber <fmt:formatNumber> 标签用于格式化数字,百分比,货币。
语言 代码
汉语(Chinese) zh
英语(English) en
德语(German) de
法语(French) fr
日语(Japanese) ja
朝鲜语(Korean) ko
国家(地区) 代码
中国(China) CN
美国(United States) US
英国(Great Britain) GB
加拿大(Canada) CA
德国(Germany) DE
日本(Japan) JP
韩国(Korea) KR
台湾(Taiwan) TW
香港(Hongkong) HK
6、<fmt:formatDate>的属性:
属性 描述 是否必要 默认值
value 要显示的日期 是 无
type DATE, TIME, 或 BOTH 否 date
dateStyle FULL, LONG, MEDIUM, SHORT, 或 DEFAULT 否 default
timeStyle FULL, LONG, MEDIUM, SHORT, 或 DEFAULT 否 default
pattern 自定义格式模式 否 无
timeZone 显示日期的时区 否 默认时区
var 存储格式化日期的变量名 否 显示在页面
scope 存储格式化日志变量的范围 否 page
<fmt:formatDate> pattern:
G 时代标志
y 不包含纪元的年份。如果不包含纪元的年份小于 10,则显示不具有前导零的年份。
M 月份数字。一位数的月份没有前导零。
d 月中的某一天。一位数的日期没有前导零。
h 12 小时制的小时。一位数的小时数没有前导零。
H 24 小时制的小时。一位数的小时数没有前导零。
m 分钟。一位数的分钟数没有前导零。
s 秒。一位数的秒数没有前导零。
S 毫秒
E 周几
D 一年中的第几天
F 一个月中的第几个周几
w 一年中的第几周 r
W 一个月中的第几周
a a.m./p.m. 指示符
k 小时 (12 小时制的小时)
K 小时 (24 小时制的小时)
z 时区
' 转义文本
'' 单引号
7、<fmt:formatNumber> 的属性:
属性 描述 是否必要 默认值
value 要显示的数字 是 无
type NUMBER,CURRENCY,或 PERCENT 类型 否 Number
pattern 指定一个自定义的格式化模式用与输出 否 无
currencyCode 货币码(当 type="currency" 时) 否 取决于默认区域
currencySymbol 货币符号 (当 type="currency"时) 否 取决于默认区域
groupingUsed 是否对数字分组 (TRUE 或 FALSE) 否 true
maxIntegerDigits 整型数最大的位数 否 无
minIntegerDigits 整型数最小的位数 否 无
maxFractionDigits 小数点后最大的位数 否 无
minFractionDigits 小数点后最小的位数 否 无
var 存储格式化数字的变量 否 Print to page
scope var 属性的作用域 否 page
<fmt:formatNumber> pattern:
0 代表一位数字
E 使用指数格式
# 代表一位数字,若没有则显示 0,前导 0 和追尾 0 不显示。
. 小数点
, 数字分组分隔符
; 分隔格式
- 使用默认负数前缀
% 百分数
? 千分数
¤ 货币符号,使用实际的货币符号代替
X 指定可以作为前缀或后缀的字符
' 在前缀或后缀中引用特殊字符
JSTL functions标签 主要是一些字符串处理的函数
三十二、Servlet
1、servlet的生命周期
实例化 ------------→ Servlet 容器创建 Servlet 的实例
↓
初始化 ------------→ 调用 init() 方法
↓
服 务 ------------→ 调用 service() 方法(doGet()或者doPost())
↓
销 毁 ------------→ 调用 destroy() 方法
↓
不可用------------→ 销毁实例并标记为垃圾收集
添加以上方法步骤:右键选择Source再选择Override...即可
例如:实现 javax.servlet.Filter 接口,实现其 init、doFilter、destroy 三个方法:
这三个方法反应了 Filter 的生命周期。
1)init:只会在 web 程序加载的时候调用,即启动如 tomcat 等服务器时调用。一般负责加载配置的参数。
2)destroy :web 程序卸载的时候调用。一般负责关闭某些容器等。
3)doFilter:每次客户端请求都会调用一次。Filter 的所有工作基本都集中在该方法中进行
三十三、过滤器
过滤器 filter
1、Filter(过滤器)用于在 servlet 之外对 request 和 response 进行修改。
Filter 有一个 FilterChain 的概念,一个 FilterChain 包括多个 Filter。
客户端请求 request 在抵达 servlet 之前会经过 FilterChain 里面所有的 Filter,
服务器响应 response 从 servlet 抵达客户端浏览器之前也会经过 FilterChain 里面所有的 Filter
2、实现自定义的 Filter 需要满足一下条件:
1)实现 javax.servlet.Filter 接口,实现其 init、doFilter、destroy 三个方法。
2)实现在 web.xml 中的配置。
3、Filter 接口有三个方法:这三个方法反应了 Filter 的生命周期。
1)init:只会在 web 程序加载的时候调用,即启动如 tomcat 等服务器时调用。一般负责加载配置的参数。
2)destroy :web 程序卸载的时候调用。一般负责关闭某些容器等。
3)doFilter:每次客户端请求都会调用一次。Filter 的所有工作基本都集中在该方法中进行。
4、在web.xml配置
每个过滤器需要配置在 web.xml 中才能生效,一个 Filter 需要配置 <filter> 和 <filter-mapping> 标签
1)<filter></filter> :配置 Filter 名称,实现类以及初始化参数。可以同时配置多个初始化参数
2)<filter-mapping></filter-mapping> :配置什么规则下使用这个 Filter
①、<url-pattern> :配置 url 的规则,可以配置多个,也可以使用通配符(*)。
②、<dispatcher> :配置到达 servlet 的方式,可以同时配置多个。
有四种取值:REQUEST、FORWARD、ERROR、INCLUDE。如果没有配置,则默认为 REQUEST。它们的区别是:
REQUEST :表示仅当直接请求 servlet 时才生效。
FORWARD :表示仅当某 servlet 通过 forward 转发到该 servlet 时才生效。
INCLUDE :Jsp 中可以通过 <jsp:include/> 请求某 servlet, 只有这种情况才有效。
ERROR :Jsp 中可以通过 <%@page errorPage="error.jsp"%> 指定错误处理页面,仅在这种情况下才生效。
③、<url-pattern> 和 <dispatcher> 是且的关系,
只有满足 <url-pattern> 的条件,且满足 <dispatcher> 的条件,该 Filter 才能生效。
5、一个 Web 程序可以配置多个 Filter ,访问有先后顺序,<filter-mapping> 配置在前面的 Filter 执行要早于配置在后面的 Filter 。
三十四、跟踪日志
引入架包,注意架包冲突;记录日志会在D盘产生相应的文件
log4j的基础知识:
1、Log4j 是 Apache 的一个开放源代码的日志记录组件,通过使用 Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI 组件、甚至是套接口服务器、NT 的事件记录器、UNIX Syslog 守护进程等;
我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码.
2、Log4j 有三个主要的组件:Loggers(记录器), Appenders (输出源) 和 Layouts(布局)
这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。
可以轻松地记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。
(1)Loggers(记录器)
在系统中被分为五个级别:DEBUG、INFO、WARN、ERROR 和 FATAL。
这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,用来指定这条日志信息的重要程度,
Log4j 的输出规则:只输出级别不低于设定级别的日志信息。
(2)Appenders(输出源)
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
配置模式:
log4j.appender.appenderName = className
log4j.appender.appenderName.Option1 = value1
…
log4j.appender.appenderName.OptionN = valueN
(3)Layouts(布局)
自定义日志输出格式,Log4j 可以在 Appenders 的后面附加 Layouts 来完成这个功能。
Layouts 提供四种日志输出样式,
如根据 HTML 样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。
四种日志输出样式使用的类如下:
org.apache.log4j.HTMLLayout(以 HTML 表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)
配置模式:
log4j.appender.appenderName.layout =className
log4j.appender.appenderName.layout.Option1 = value1
…
log4j.appender.appenderName.layout.OptionN = valueN
3、Log4j 支持两种配置文件格式,一种是 XML 格式的文件,一种是 properties 属性文件。常用properties文件
4、配置log4j
(1)、配置根 Logger:
log4j.rootLogger = [level] , appenderName1, appenderName2, …
log4j.additivity.org.apache=false:表示 Logger 不会在父 Logger 的 appender 里输出,默认为 true。
注:
level :设定日志记录的最低级别,可设的值有 OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL
appenderName:就是指定日志信息要输出到哪里。可以同时指定多个输出目的地,用逗号隔开。
(2)、配置日志信息输出目的地(appender)
log4j.appender.appenderName = className
注:
appenderName:自定义 appderName,在 log4j.rootLogger 设置中使用;
className:可设值有5个
选项Option:
共有选项:
Threshold=WARN:指定日志信息的最低输出级别,默认为 DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为 false 则不输出,默认值是 true。
输出源的:
1)ConsoleAppender 选项:
Target=System.err:默认值是 System.out。
2)FileAppender 选项:
Append=false:true 表示消息增加到指定文件中,false 则将消息覆盖指定的文件内容,默认值是 true。
File=D:/logs/logging.log4j:指定消息输出到 logging.log4j 文件中。
3)DailyRollingFileAppender 选项:
Append=false:true 表示消息增加到指定文件中,false 则将消息覆盖指定的文件内容,默认值是 true。
File=D:/logs/logging.log4j:指定当前消息输出到 logging.log4j 文件中。
DatePattern='.'yyyy-MM:每月滚动一次日志文件,即每月产生一个新的日志文件。当前月的日志文件名为 logging.log4j,前一个月的日志文件名为 logging.log4j.yyyy-MM。
另外,也可以指定按周、天、时、分等来滚动日志文件,对应的格式如下:
1)'.'yyyy-MM:每月
2)'.'yyyy-ww:每周
3)'.'yyyy-MM-dd:每天
4)'.'yyyy-MM-dd-a:每天两次
5)'.'yyyy-MM-dd-HH:每小时
6)'.'yyyy-MM-dd-HH-mm:每分钟
4)RollingFileAppender 选项:
Append=false:true 表示消息增加到指定文件中,false 则将消息覆盖指定的文件内容,默认值是 true。
File=D:/logs/logging.log4j:指定消息输出到 logging.log4j 文件中。
MaxFileSize=100KB:后缀可以是 KB, MB 或者 GB。在日志文件到达该大小时,将会自动滚动,即将原来的内容移到 logging.log4j.1 文件中。
MaxBackupIndex=2:指定可以产生的滚动文件的最大数,例如,设为 2 则可以产生 logging.log4j.1,logging.log4j.2 两个滚动文件和一个 logging.log4j 文件。
(3)、配置日志信息的输出格式(Layout):
log4j.appender.appenderName.layout=className
className:可设值4个
选项:
(1)HTMLLayout 选项:
LocationInfo=true:输出 java 文件名称和行号,默认值是 false。
Title=My Logging: 默认值是 Log4J Log Messages。
(2)PatternLayout 选项:
ConversionPattern=%m%n:设定以怎样的格式显示消息。
格式化符号说明:
%p:输出日志信息的优先级,即 DEBUG,INFO,WARN,ERROR,FATAL。
%d:输出日志时间点的日期或时间,默认格式为 ISO8601,也可以在其后指定格式,如:%d{yyyy/MM/dd HH:mm:ss,SSS}。
%r:输出自应用程序启动到输出该 log 信息耗费的毫秒数。
%t:输出产生该日志事件的线程名。
%l:输出日志事件的发生位置,相当于 %c.%M(%F:%L) 的组合,包括类全名、方法、文件名以及在代码中的行数。例如:test.TestLog4j.main(TestLog4j.java:10)。
%c:输出日志信息所属的类目,通常就是所在类的全名。
%M:输出产生日志信息的方法名。
%F:输出日志消息产生时所在的文件名称。
%L: 输出代码中的行号。
%m: 输出代码中指定的具体日志信息。
%n:输出一个回车换行符,Windows 平台为 "rn",Unix 平台为 "n"。
%x:输出和当前线程相关联的 NDC(嵌套诊断环境),尤其用到像 java servlets 这样的多客户多线程的应用中。
%%:输出一个 "%" 字符。
另外,还可以在 % 与格式字符之间加上修饰符来控制其最小长度、最大长度、和文本的对齐方式。如:
1) c:指定输出 category 的名称,最小的长度是 20,如果 category 的名称长度小于 20 的话,默认的情况下右对齐。
2)%-20c:"-" 号表示左对齐。
3)%.30c:指定输出 category 的名称,最大的长度是 30,如果 category 的名称长度大于 30 的话,就会将左边多出的字符截掉,但小于 30 的话也不会补空格。
log4jdbc是工作在jdbc层的一个日志框架,能够记录SQL及数据库连接执行信息。
#记录系统执行过的 sql 语句
#log4j.additivity.jdbc.sqlonly=true
log4j.logger.jdbc.sqlonly=DEBUG,appenderName
#控制台输出
log4j.appender.appenderName=org.apache.log4j.ConsoleAppender
#控制台输出格式定义
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n%n
#记录 sql 执行的时间,可以分析耗时的 sql 语句
#log4j.additivity.jdbc.sqltiming=true
#log4j.logger.jdbc.sqltiming=INFO,console
#记录除了 ResultSet 外的所有 JDBC 调用情况。一般不需要。
#log4j.additivity.jdbc.audidt=true
#log4j.logger.jdbc.audit=INFO,console
#记录返回结果集信息
#log4j.additivity.jdbc.resultset=true
#log4j.logger.jdbc.resultset=INFO,console
#记录数据库连接和释放信息,可记录当前的数据库连接数,便于诊断连接是否释放
#log4j.additivity.jdbc.connection=true
#log4j.logger.jdbc.connection=INFO,console
三十五、单元测试:
单元测试
1、单元测试的使用步骤:
(1)选中要测试的项目右键Properties-JavaBuildPath-Libraries-AddLibraries-JUnit-JUnit4点击Finish即可
(2)选中要测试的项目右键New新建Source Folder里面填写测试文件名称如:test
(3)在src下面选中你要测试的类方法,然后New-other-搜索框查询JUnit接着进入JUnitTestCase在Source folder重选要测试的文件如:ThisDemoWeb/test,之后点击Next选择要测试的类方法;在代码块右键点击RunAs会显示JUnit Test最后点击测试
(4)在test中建立的测试类下进行编写代码测试即可
2、几个常用的注解:
@Test:把一个方法标记为测试方法
@Before:每一个测试方法执行前自动调用一次
@After:每一个测试方法执行完自动调用一次
@BeforeClass:所有测试方法执行前执行一次,在测试类还没有实例化就已经被加载,需要用static修饰;通常用来初始化资源。
@AfterClass:所有测试方法执行完执行一次,在测试类还没有实例化就已经被加载,需要用static修饰;通常用来关闭资源。
@Ignore:暂不执行该测试方法
3、@Test的两个属性
excepted 用来测试异常的
timeout
4、注意:JUnit4为了保证每个测试方法都是单元测试,是独立的互不影响。所以每个测试方法执行前都会重新实例化测试类。
三十六、线程安全:
进程 线程 线程安全 视频23分开始
(一)、进程基本概念
1、进程的特性:
独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间
动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念。进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的
并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响
并发性(concurrency)和并行性(parallel)是两个概念,并行指在同一时刻,有多条指令在多个处理器上同时执行;并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果
2、线程的特性:
(二)、实际案例看E:\javaStudy\20180426\src\com\gx\thread目录下的相关内容
进程符合:“加锁-修改-释放锁”的逻辑
Demo01:主要提到调用start关键字来启动线程(注意:不能直接调用方法)
Demo02:使用关键字Runnable实现接口方法启动进程
Demo03:主要涉及到设置线程的优先级、验证线程只能start一次、注意线程休眠Thread.sleep(1000)以及进程死亡等内容
Demo04:测试进程周期的运转,此方法会导致账户余额出现问题
Demo05:解决多线程同时运行的问题:需要运用到synchronized(锁对象)以及继承Account里面的方法;使account作为同步监视器(锁对象),任何线程进入下面同步代码块之前必须先获得对account的锁
Demo06:主要内容跟Demo05的功能一样,区别于它能直接调用AccountSyn类里面的内容即可
Demo07:用AccountLock里面的方法,直接调用lock方法加锁,提供给Demo07_TakeMoney4类使用
Demo08:定义多个类来实现同步方法的进程
Demo09:在类里设计多个进程方法,用notify关键字叫醒另外一个线程进行循环测试
Demo10:在类里设计多个进程方法,用NotifyAll关键字同时叫醒多个线程
三十七、数据结构
1、数据结构基本功能:
1、如何插入一条新的数据项
2、如何寻找某一特定的数据项
3、如何删除某一特定的数据项
4、如何迭代的访问各个数据项,以便进行显示或其他操作
2、常见的数据结构:数组Array 栈Stack 队列Queue 链表Linked List 树Tree 哈希表Hash 堆Heap 图Graph
3、java.util包中三个重要的接口及特点:List(列表)、Set(保证集合中元素唯一)、Map(维护多个key-value键值对,保证key唯一)。其不同子类的实现各有差异,如是否同步(线程安全)、是否有序。
(一)、算法的五个特征:
1、有穷性:对于任意一组合法输入值,在执行又穷步骤之后一定能结束,即:算法中的每个步骤都能在有限时间内完成
2、确定性:在每种情况下所应执行的操作,在算法中都有确切的规定,使算法的执行者或阅读者都能明确其含义及如何执行。并且在任何条件下,算法都只有一条执行路径
3、可行性:算法中的所有操作都必须足够基本,都可以通过已经实现的基本操作运算有限次实现之
4、有输入:作为算法加工对象的量值,通常体现在算法当中的一组变量。有些输入量需要在算法执行的过程中输入,而有的算法表面上可以没有输入,实际上已被嵌入算法之中
5、有输出:它是一组与“输入”有确定关系的量值,是算法进行信息加工后得到的结果,这种确定关系即为算法功能
(二)、算法的设计原则
1、正确性
2、可读性
3、健壮性
4、高效率与低存储量需求
三十八、jdbc增删查改
(一)、查询步骤:
1、加载驱动的Jar包:Class.forName("com.mysql.jdbc.Driver");
2、通过DriverManager打开数据的链接
String url="jdbc:mysql://localhost:3306/domedb";
String user="root";
String password ="1234";
conn= DriverManager.getConnection(url, user, password);
3、通过Connection对象创建Statement对象或者PreparedStatement
String sql="SELECT *FROM urse"; //查询数据库表
ps =conn.prepareStatement(sql);
4、执行并返回结果
rs =ps.executeQuery();
5、遍历结果 注意:这里的序号(索引)是从1开始
while(rs.next()){
System.out.println("id:"+rs.getInt(1)+" name:"+rs.getString(2)+" password:"+rs.getString("password"));
}
6、关闭资源
finally{
//回收资源包括关闭Connection、 Statement、ResultSet 等资源
try {
if(conn !=null){
conn.close();
}
if (ps !=null) {
ps.cancel();
}
if(rs !=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
实际案例:
package com.gx.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 事务
* 原子性(Atomicity):事务是应用中最小的执行单位,事务是应用中不可再分的最小逻辑执行体。
* 一致性(Consistency):事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务成功提交的结果时,数据库处于一致性状态。
* 隔离性(Isolation):各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务都 是隔离的。
* 持续性(Durability):持续性也称为持久性(Persistence),指事务一旦提交,对数据所做的任何改变都要记录到永久存储器中,通常就是保存进物理数据库。
*/
public class JdbcDemo {
public static void main(String[] args) {
//全局变量
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
/**
* 加载驱动的Jar包
* 找到驱动下面com.mysql.jdbc里面对应的Driver右键Copy Quafaulid Name复制报名即可
* 不同的数据库引用不同的包
* mysql com.mysql.jdbc.Driver
* oracle oracle.jdbc.driver.OracleDriver
* sqlserver com.microsoft.sqlserver.jdbc.SQLServerDriver
*/
Class.forName("com.mysql.jdbc.Driver");
//通过DriverManager打开数据库的链接
String url="jdbc:mysql://localhost:3306/domedb";
String user="root";
String password ="1234";
conn= DriverManager.getConnection(url, user, password);
/**
* 1.PreparedStatement是预编译的,对于批量处理可以大大提高效率. 也叫JDBC存储过程
* 2.使用 Statement 对象。在对数据库只执行一次性存取的时侯,用 Statement 对象进行处理。PreparedStatement 对象的开销比Statement大,对于一次性操作并不会带来额外的好处。
* 3.statement每次执行sql语句,相关数据库都要执行sql语句的编译,preparedstatement是预编译得,preparedstatement支持批处理
* 4.用PreparedStatement对象安全性更好。传递给PreparedStatement对象的参数可以被强制进行类型转换,使开发人员可以确保在插入或查询数据时与底层的数据库格式匹配。
*/
//3、通过Connection对象创建Statement对象或者PreparedStatement
//Statement statement=con.createStatement();
//PreparedStatement 一般使用PreparedStatement
String sql="SELECT *FROM urse"; //查询数据库表
ps =conn.prepareStatement(sql);
//4、执行并返回结果
rs =ps.executeQuery();
//5、遍历结果集 注意:这里的序号(索引)是从1开始 ! ! !
while(rs.next()){
System.out.println("id:"+rs.getInt(1)+" name:"+rs.getString(2)+" password:"+rs.getString("password"));
}
//抛异常
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
//6、关闭
finally{
//回收资源包括关闭Connection、 Statement、ResultSet 等资源
try {
if(conn !=null){
conn.close();
}
if (ps !=null) {
ps.cancel();
}
if(rs !=null){
rs.close();
}
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
(二)、新增步骤:
1、先初始化固定的全局变量
Connection conn=null;
PreparedStatement ps =null;
ResultSet rs =null;
2、同样的加载Jar包
Class.forName("com.mysql.jdbc.Driver")
3、链接mysql数据库
String url="jdbk:mysql://localhost:3360/domedb";
String user="root";
String password ="1234";
conn=DriverManager.getConnection(url,user,password);
4、获取要新增的表信息
String sql ="INSERT INTO URSE (NAME,PASSWORD,ROLEID) VALUE(?,?,?)";
ps=conn.prepareStatement(sql);
5、新增的数据信息,行索引从1开始
ps.setString(1,"sili");
ps.setString(2,"135");
ps.setInt(3,1);
6、判断是否新增成功(executeUpdate 返回受影响的行数)
int r =ps.executeUpdate();
if(r >0){
System.out.println("新增成功");
}
7、关闭及回收资源等操作
finally{
try{
if(conn !=null){conn.close();}
if(ps !=null){ps.close();}
if(rs !=null){rs.close();}
}
catch(Exception e){
e.printStackTrace();
}
}
实际案例:
package com.gx.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class jdbcInsert {
public static void main(String[] args) {
//定义全局变量
Connection conn=null;
PreparedStatement ps =null;
ResultSet rs =null;
try {
//1、加载Jar包
Class.forName("com.mysql.jdbc.Driver");
//2、链接SQL数据库
String url ="jdbc:mysql://localhost:3306/domedb";
String user ="root";
String password ="1234";
conn=DriverManager.getConnection(url, user, password);
//获取要新增的表信息
String sql = "INSERT INTO urse (NAME,PASSWORD,roleid) VALUE(?,?,?)";
ps=conn.prepareStatement(sql);
//新增的数据 索引从1开始
ps.setString(1, "sili");
ps.setString(2, "135");
ps.setInt(3, 1);
//executeUpdate 返回受影响的行数
int r =ps.executeUpdate();
if(r >0){
System.out.println("新增成功");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
//回收资源包括关闭Connection、 Statement、ResultSet 等资源
finally{
try {
if(conn !=null){
conn.close();
}
if(ps !=null){
conn.close();
}
if(rs !=null){
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
(三)、修改实际案例:步骤和新增大同小异
package com.gx.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JdbcUpdate {
public static void main(String[] args) {
//定义全局变量
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs =null;
try {
//加载Jar包
Class.forName("com.mysql.jdbc.Driver");
//链接mysql数据库
String url ="jdbc:mysql://localhost:3306/domedb";
String user ="root";
String password ="1234";
conn=DriverManager.getConnection(url, user, password);
//获取对应要修改的表信息
String sql ="UPDATE urse SET NAME=?,PASSWORD=? WHERE id=?";
ps=conn.prepareStatement(sql);
//修改表信息
ps.setString(1, "coco");
ps.setString(2, "678");
ps.setInt(3, 2);
//判断修改成功否
int r =ps.executeUpdate();
if(r >0 ){
System.out.println("修改成功");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
finally{
try {
if(conn !=null){
conn.close();
}
if(ps !=null){
ps.close();
}
if (rs !=null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
(四)、删除实际案例:
package com.gx.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JdbcDelete {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
String url ="jdbc:mysql://localhost:3306/domedb";
String user ="root";
String password ="1234";
conn=DriverManager.getConnection(url, user, password);
String sql="DELETE FROM urse WHERE id=?";
ps =conn.prepareStatement(sql);
ps.setInt(1, 1);
int r =ps.executeUpdate();
if (r >0) {
System.out.println("删除成功");
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//回收资源包括关闭Connection、 Statement、ResultSet 等资源
finally{
try {
if (conn!=null) {
conn.close();
}
if (ps!=null) {
ps.close();
}
if (rs!=null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
三十九、后台增删查改
java一切文件不允许放在中文的目录下
(一)、增删查改的存放代码步骤:(系统设置-->用户类型设置)
1、在servlet包新建MainServlet类,继承HttpServlet以及重写doGet和doPost方法;再写页面跳转main和mainIndex
2、在service.impl包新建UserTypeServiceImpl类并继承IUserTypeService以及重写对应的数据类型方法
3、在WebRoot中jsp里面新建userType下新建list类(里面主要内容是:布局列表信息)
4、在dao.impl中新建UserTypeDaoImpl类及重写增删查改的方法(从中查询数据等信息);并继承IUserTypeDao方法以及在po包里面UserType类的用户信息
5、在service中新建UserTypeServiceImpl和新建IUserTypeService;接着UserTypeServiceImpl需要继承IUserTypeService并实现相关的类型方法块
6、在servlet中新建UserTypeServlet,在里面编写增删查改的跳转页面已经相关实现业务代码;再userType下新建insert.jsp和update.jsp的页面设计代码
(二)、数据库时间处理:
1、java主要分别有:date time datetime timestamp四种时间类型
2、time datetime timestamp是在date的基础之下分支出来的
3、实例:在po包里面的Users.java中定义:
private Date opDatetime;
public Date getOpDatetime() {
return opDatetime;
}
public void setOpDatetime(Date opDatetime) {
this.opDatetime = opDatetime;
}
(三)、增删查改:(系统设置-->人员设置)
list查询
1、在dao.impl包下修改UsersDaoImpl,先对增删查改进行数据库的查询;接着再对重写方法进行代码编辑
2、在数据库users表添加时间字段(op_datetime)
3、在service.impl中UsersServiceImpl处理一下重写方法并实例化dao下面的方法(IUserDao usersDao = new UserDaoImpl();)
4、在servlet新建UsersServlet;之后记得配置web
5、在vo新建分页Bsgrid(跟以前类似)
6、在jsp文件下新建users文件包下实现list查询、insert新增、update修改的页面布局代码
7、在assets中的mycustom里面的js的mycustom.js处理一下时间问题
(四)、增删查改和文件上传
insert新增
update修改
delete删除
upload、download文件上传下载
1、在项目文件之外或其他文件夹下面新建UpLoad文件存放上传下载图片
2、文件上传注意点:依赖两个jar包(commons-fileupload-1.x.x.jar)(commons-io-x.x.jar)
表单 method 属性应该设置为 POST 方法,不能使用 GET 方法。
表单 enctype 属性应该设置为 multipart/form-data.
表单 action 属性应该设置为在后端服务器上处理文件上传的 Servlet 文件
多个文件上传,设置多个 name 属性值不同的 input 标签
3、json需要的jar包
commons-beanutils-1.9.2.jar
commons-collections-3.2.1.jar
commons-lang-2.4.jar
commons-logging-1.1.1.jar
ezmorph-1.0.6.jar
json-lib-2.4-jdk15.jar
数据库字段
封装基本信息:主键id、主键名称、数据库链接、分页、行数、总行数、查询、新增、修改、删除
jsp架包分别有:界面设计(包含:包引用、link链接、页面设置、JS、JQuery、script:表格设置、打开增删查改的链接代码、以及自定义内容)
四十、搭建简单的项目
(一)、新建 web Project
com
|-gx
|-servlet/web/controller 放 servlet
|-service 放服务层的接口
| |-impl 服务接口的实现类
|-dao 数据库操作接口
| |-impl 数据库操作接口的实现类()
|-po 数据的实体类
|-vo
|-common 放公共的类
|-filter 过滤器
|-util 放工具类
dao(数据访问对象):持久层,主要负责与数据库打交道,从模式的角度来说,dao中不应该有业务逻辑
dto(数据传输对象):层间传递参数的对象;早期,方法的参数都是直接填写的,如:void method(int i,int j);
service(BO):服务层,又叫业务层,我个人觉得业务层比较贴切;早期有一帮人把这一层成为BO(业务对象)
controller(action) : 这货是mvc中的‘c’,属于web前端,位于view与service层之间
dao(持久层接口),daoimpl(持久层实现),filter(过滤器),po(数据实体类包),service(业务层接口),
serviceimpl(业务层实现),servlet(UI页面业务实现),util(工具类包),vo(其他实现类)interceptor(拦截器)
(二)、编写web主要包括:html,css,JS,javascript,JQuery,bootstrap,Ajax,images等,还有就是jsp,或者模版文件了
(三)、搭建项目步骤:
1、先在SQL新建一个demoweb的数据库,里面建两个表:user_type和users主要用于登录使用
2、在myeclipse里面新建项目,将固定的包拷贝过来
3、接着在com.gx.util包中配置DBUtil数据库文件及改写数据库链接jdbc.properties的数据库名称
4、接着在com.gx.po包下面建一个用户信息users(信息必须备注)
5、在com.gx.common包中建接口类(interface)BaseDao来封装基础dao以及BaseService来封装基础service
......
(四)、引入架包:
方法一:在该项目右键选择Properties之后选Java Build Path 接着选择右边Add External JArs...选择要使用的架包即可
方法二:找到WebRoot下面的WEB-INF文件下,粘贴在lib即可(报错情况下可以考虑使用)
注意:架包冲突,架有一样的或者版本不同的相同架包不允许重复引入
(五)、手动设置密码为加密类型:date users set password =md5('123456') where user_id=2
(六)、com.gx.util.ValidateImage 验证类
来源:CSDN
作者:农村小白
链接:https://blog.csdn.net/weixin_44538107/article/details/87865898