JAVA(强类型语言)
java 跨平台:
跨平台:windox linux 等
通过JVM java虚拟机实现,不同平台对应的jvm
JRE/JDK:
JRE:运行环境,包括JVM和核心类库。 --想运行java语音,只需要安装JRE就可以了。
JDK:java程序开发工具包 包括JRE和开发人员使用工具(javac.exe和java.exe)
–编译:
javac 路径
javac I:\java-study\s1.java
–运行:
路径下:java +文件(不要加后缀)
java s1
所以:
JDK>JRE>JVM
JDK=JRE+开发工具;
JRE=JVM+核心类库;
基础语法:
1.注释:
1. 单行 //
2. 多行/* 注释内容*/
3. 文档注释/** 注释内容 */
2.关键字:
字母全部小写:public static final void 等
3.常量:
一个值是不变的,就是常量;像字符串,整数,小数,字符,boolean null 这些常量
常量在JVM中存放在常量池中,常量池在内存位置:
jdk1.7前:永久代;
jdk1.7 :堆内存中
jdk8移除了永久代并由元空间(metaspace)代替,存放在本地内存(native space)中。并没有对常量池再做变动。即常量池一直在堆中。
4.数据类型:(强类型语言)
计算机存储最小信息单元:最小为 位bit 通常用b。、
计算机种最小的存储单元: 字节byte 通常用B 由8个位组成。–宽带的10M代表b,即下载速度才1.25MB
1.基本数据类型:
1.1整数
byte 1B
short 2B
int 4B --默认类型为int
long 8B
1.2浮点数
float 4B
double 8B --默认类型为double
1.3字符
char 2B --char对应的unicode的对应编码
1.4布尔
boolean 1b
2.引用数据库类型--是由类,接口,数组组成 String
5.变量:
例 int a = 10 ; a就是变量
1.同一个方法不能有重复;
2.定义变量一定要赋值;
3.long l = 10000L; --取消默认
float =1.1f; --不然double 在float中放不下会报错;
6.标识符:
1.数字,字母,_,$组成;
2.不能以数字开头;
3.不能是关键字,且区分大小写;
小驼峰:firstName;
大驼峰:FirstName,Student;
7.类型转换:
1.自动装换:将一个表示范围小的数值放到范围大的变量;
double d = 10; --d为10.0;
byte<short=char<int<long<float<double
2.强制转换:将一个表示范围大的数值放到范围小的变量(不建议,会有数据丢失)
int a = (int)22.88; --a=22;
8.运算符
8.1算术运算符:
8.1.1 + - * / %
注意:1.除法得到的时商,取余得到的余数
2.要想得到小数,除数中有浮点数参与
8.1.2 字符的‘+’:字符在计算机加操作中,对应的数值是底层的数值;
int i=2;
char j='A';
System.out.println(i+j); --75 (int类型。不同类型加运算,会自动升级为高级的)
8.1.3 字符串的加操作:
String+int --为拼接 aaa666
"aaa"+1+1 --aaa11
1+1+"aaa" --2aaa(体现了拼接是从前往后的)
8.2 赋值运算符:
=,+=,-=,*=,/=,%= :就是给变量赋值的,但是后面5个扩展的运算符隐含了强制类型转换
注:
short s = 10;
s = (short) (s+10); --如果结果需要用short类型的s接受,则因为+的10为int,所以需要强转,将int强转为short
s+=10; --这就不用,因为+=隐含了强制类型转换(因此推荐这样写法)
8.3自增自减运算符:
-- ++ 放在变量前后有差异。
int i = 10 ;
i++; 先运算,后加1
i--; 先运算,后减1
++i; 先加1,后运算
--i; 先减1,后运算
8.4关系运算符:
==
!=
>
<
>=
<=
结果是boolean类型 , ==为判断,=为赋值
8.5逻辑运算符:
8.5.1:基本逻辑运算符:
& 逻辑与
| 逻辑或
^ 逻辑异或 -->两边一样为false,不同为true
! 逻辑非
以上可以进行逻辑判断 :
(i<2)|(i>4) --返回boolean类型,但是i=3时,false|false --> false 不会短路
8.5.2:短路逻辑运算符:
&& 与
|| 或
8.6三元运算符:
关系表达式?表达式1:表达式2;
关系表达式->true 结果为:表达式1 ;
关系表达式->false 结果为:表达式2 ;
em: int max=1>2? 1:2;
9. 数据输入:
Scanner使用;
java.util.Scanner;
Scanner s = new Scanner(System.in);
int i = s.nextInt(); -- 输入的是int类型
10.分支语句:
–day2
控制语句:
1.控制选择if else if() switch
1.1 if 多条判断:
if(条件1) {
任务1;
}else if(条件2) {
任务2;
}else {
任务3;
}
1.2 switch
switch(int或者String类型的字面量或者变量){ // String 在jdk7后才能使用
case int或者String类型的字面量或者变量:
java;
…
break;
case int或者String类型的字面量或者变量:
java;
…
break;
case int或者String类型的字面量或者变量:
java;
…
break;
…
default :
java;
…
}
上面是默认写法,case合并写法如下,原理是用case穿透:
switch(i){
case 1: case2 :case 3 :
java;
break;
…
}
2.循环结构for while do…while()
1:for(定义变量 ;条件;变量变化 ){
java;
…
}
2. while(boolean){
java;
…
}
3. do{
java;
}while(boolean);
3.控制循环break continue
3.1 break;中断
for(){
break; --跳出循环,终止循环执行;for循环结束 --但是不会影响外层for循环
}
想要跳出多重循环,可以命名外层循环名称或者加标识位。
3.2 continue:
for(..){
if(..){
continue; --跳出当前条件循环,单for仍然继续,只是当前执行结束
}
.、..
}
方法:
修饰符列表 返回值类型 方法名(形式参数列表){ //形参是局部变量 --只有它是对象时候,传过来是个地址,才能改变
方法体;
}
1.方法内存分配:
数据结构:
栈:先进后出,只有栈顶的元素具有活跃状态,栈针一直指向栈顶元素
堆:
方法区内存:最先有数据,因为方法执行最先把class文件装载到虚拟机中
方法执行时候内存在栈,所以栈的活动最频繁,调用方法就是在栈里分配空间,就是压栈。
2.方法重载:overload
3.方法递归
数组:
声明1:
int[] a; --未初始化,未分配空间 @@堆
int[] b=null; --@@栈
int[] c={1,2,3};//只能在声明时使用。
栈内存:大小确认,后进先出,主要是基本类型;
堆内存:大小不确定,存放对象类型的;
String[] 在args中,args在栈内,String[]对象在堆中,args中存放的是指向String[]的指针(引用)
声明2:
int[] a=new int[3]; --长度为3的整型数组
char[] b = new char[3]; --长度为3的字符数组
int[] c=new int[] {10,20,30};
a=new int[] {10,20,30} --赋值1
b[0]=10;
b[1]=10;
b[2]=10; --赋值2
int[] a={20,20,10} --声明时初始化
//动态初始化
int[] a1 = new int[3];
a1[0]=0;
a1[1]=1;
// 静态初始化
int[] a2 = new int[] {1,2,3};
数组属性:a2.length; --数组长度
数组长度固定,有序且连续,若是为赋值,则该位置默认数字为该类型的默认值;数字类型0,对象为null
--多维数组:
二维数组:int[][] a3 = new int[][]{
{1,2},{3,4}
};
声明:int[][] a4 = new int[2][3]; 2*3;
--常见算法:
面向对象:
面向对象OOP;面向过程POP;
1.POP强调的时功能行为,OOP强调将功能封装进对象,强调具备了功能的对象。
2.OOP更加强调运用人类的日常思维逻辑采用的思想方法与原则,如抽象,分类,继承,聚合,多态等。
OOP三大特征
1.封装;private
2.继承;override
3.多态;overload
Java类成员:
方法:就是函数;
属性:成员变量;
实例化:创建具体对象;
静态的: public static String name = "wuguoqing";
可以用:类名.属性 ; 直接调用,称为类变量;
代码块:
{//代码块
System.out.println("================");
this.name="wang";
}
static { //静态块,在类加载时候执行的,早于main方法,只执行一次,因为class只加载一次
System.out.println("static");
}
匿名对象:
new Student().read(); 不将声明的对象赋值而调用方法,但只适用一次。
方法重载overload:
同一个类中允许存在同一方法名的方法,只要参数的:个数,参数类型不同即可--通过入参辨别;
方法的可变个数的参数:
public void test(String[] detail){}; --将入参写成数组,这样入参就存在动态变化
public void test(String... detail){}; --用java特有的方式,实现可变,detail和数组相同,
public void test(int a , String... detail){}; --但是有其他类型的参数,要放在后面
方法参数传递:
栈stack:基本数据类型8种(地址+数据),对象的引用(地址);
堆heap: 所有的对象(包括自己定义的对象和字符串对象)的new object()的内容;
方法区method:所有的class和static 变量;
##--所以java的方法传递,基础类型时,是复制的值传递,方法无法改变调用主方法的参数
但是,传递对象时候(引用对象),传递的时复制的对象,方法修改地址的对应堆的对象
,所以入参对象地址不变,但是对象的数据发生改变。
包package和引用import:
export ->到处为jar类型。通常的jar包;
import ->代码中找到jar包的具体位置;
例如:java.lang ->String
java.net ->执行网络相关类和接口
java.io ->输入、输出
java.util ->集合,日期等
java.text ->java格式化相关
java.sql ->JDBC
java.swt ->图形用户界面GUI
封装隐藏:
private --只在本文件本调用
default(不写也行) -- 同一个包内多个java文件都能调用
protected --不仅同一个包,子类也能调用
public --都可以调用
构造方法:
1.不写,默认为有一个空的,new String();什么参数都没有的,但是写了,这个默认的就取消了;
2.类的修饰是什么,构造就是什么修饰,比如内部类,default,那么它的构造就是default(不写)
例如:
public class P{
public P(){
}
}
3.父类的构造器不能被子类继承。
@@0.static静态块,可以在main之前执行,因为它是类加载时执行,早于mian(但只能执行一次,因为加载只加载一次)
1.new通知jvm创建对象,分配内存,实训化;
数:0;
Boolean: false;
char : '';
object: null; --第一次初始化:按属性进行缺省初始化;
@@1-2:可以进入代码块进行:能进行初始化,但是不能获得参数, 是写死的;
2.进入构造方法:(构造初始化:第二次初始化)
给已经分配内存的变量进行赋值;
3.new完成,赋值给变量:
this关键字:
1.当前对象的引用:
public calss Person{
private String name ;
public Persion(String name){
this.name = name; // 可以用以区分属性和形参
}
}
2.this() --这种方式来调用构造,放在其他构造方法中:
(1)但是必须放在首行;
(2)不许自己调自己(构造方法);
JavaBean:
属性一般私有,可以称为实体类。
继承:
public class A extends B {
A 继承 B 类的属性和方法;
}
1.提高代码复用性;
2.实现多态
3.不能为了使用相近属性而继承,狗继承人的性别属性,这样逻辑不通
4.子类不能访问父类私有的,只能访问protected ,public
5.java只支持单继承:不能多继承,所以需要多层继承
方法重新:override:
1.子类重写父类方法,只是重新写方法体
2.子类重写,不能使用比父类更严格的访问权限,如父类是public,子类只能是public
super:
用来调用父类的属性和方法(子类之上的所有父类层级)
多态:
1.方法的重载重写;
2.对象的多态性--直接应用在抽象类和接口上
->声明父类,实现子类;--子类可以看成特殊的父类,那么该变量不能访问子类的属性方法
equals():
字符串的比较内容
装箱拆箱:
主要应用:基本数据类型和字符串的转换
toString();父类Object的toString()方法就是输出当前对象的内存地址,如果要输出其他信息,需要重写方法;
static:
静态的:描述的属性,则是类属性,被所有实例化对象共享,使用时要慎重,因为只要一改,所有类都会变化;
类方法:工具类用的比较多,通过类名.方法名调用。
单例设计模式:
设计模式:解决问题的思考方式;
单例:只要一个实例,实例化对象;(只会new 一次)
使用环境:实例化消耗大量时间资源;
懒汉式:
private Single(){} //构造私有化
private static Single single = null;
public static Single getInst(){ //只能通过共有的getInst()获取实例
if(single==null){
single = new Single();
}
return single;
}
饿汉式:
private Single(){} //构造私有化
private static Single single = new Single();
public static Single getInst(){ //只能通过共有的getInst()获取实例
return single;
}
懒汉饿汉区别就是什么时候new这个对象。
初始化块:
{}/static{} --对类的成员初始化,静态的开发用的多些,初始化类的静态一些属性
final:
1.final修饰类,类不能被继承;
2.修饰方法,则不能被子类重写;
3.修饰变量,则只能初始化一次。
即final最终版。
抽象类:abstract class B
A extends B
1.需要将抽象类中所有抽象方法全部实现,不然A还是抽象的
2.只能继承一个抽象类;
3.抽象类中,抽象方法可以没有方法体。
4.抽象类不能实例化,只能作父类。
5.不能用abstract 修饰,属性,私有方法,构造器,静态方法,final方法; --因为要实现
模板方法设计模式:
抽象类为模板,子类是实现的不同设计模式;
接口:
实现多重继承效果:
public interface A{
}
1.成员变量:public static final修饰的;
2.方法都是public abstract 修饰的;
3.没有构造器;
4.多重继承
5.子类没有实现全部的抽象方法,子类仍是抽象类
public B inplements A ,C...{
}
--接口和抽象类的异同;
同:接口是抽象的,抽象类也是抽象的,都不能实例化,只能被继承。
如果一个抽象类,所有属性都是public static final 所有的方法都是public abstract.可以将这个抽象类,申明为接口。
类之间继承是extends,接口之间继承也是extends;
异:抽象类只能单继承,接口可以多继承;
接口中所有属性都是public static final 的,抽象类中可以有它的修饰符;
接口中所有方法都是public abstract 方法,抽象类中方法可以实现的,也不必是public
类之间继承用的extends,类继承接口使用的是:implements;
--工厂模式:
将类的声明写到公共方法中。
通过工厂把new对象给隔离,通过产品的接口可以接受不同实际产品的实现类。
--内部类:
1.普通内部类:
2.静态:
和普通一样,其实是一个顶级模板,只不过定义在类里面,可以通过OuterClass.InnerClass 访问;
3.局部:
局部内部类:可以直接访问方法中的局部变量,外部类中的属性
内部类与各部类兼容情况下,通过,外部类类名.this.属性名来区分
4.匿名:
实际上是创建一个零时的没有类名的指定类的子类对象。创建一个新功能的对象,而不再意定义的一个类;
异常:
ERROR:系统问题
Exception:代码问题
捕获异常:try catch finally
抛出异常:throw--手动抛出 throws--方法上
集合:java.util
集合中存放的是各个基本类型的引用类型
java集合分为三个大类:
Set: 无序,不可重复的集合
List:有序,可重复的集合
Map:具有映射关系的集合
1.Set :
HashSet : <-Set接口 <- Collection接口
1.无序
因为存放元素时,会调用hashCode()的方法获取该对象的hashCode值,后根据hashCode值
决定存放位置。
2.不可重复的
当两个元素的equal()方法返回true,但是hashCode不相同,HashSet会存在不同位置,
但依然可以添加成功。
3.线程不安全
4.元素可以是null,但是只能存一个null
Set set = new HashSet(); //当没有范型限制时,添加只要是Object类型就行
set.add(Object); //添加
set.romove(1) ; //删除
set.contains("a") //判断是否存在
set.clear(); //清空
set.size(); //集合大小int
// 使用迭代器遍历
Iterator it = set.iterator();
while(it.hasNext()){
syso(it.next())
}
// 使用foreach遍历
for(Object i : set){
syso(i);
}
TreeSet : <- NavigableSet接口 <- SortedSet接口 <- Set接口 <- Collection接口
1.可以确保集合元素处于排序状态,支持两种排序方式,自然排序和定制排序,默认情况下
采用的时自然排序。
自然排序:
按照大小从小到大排序,所以类型要一样,不然会异常。
定制排序:
实现Comparator<Object>接口,重写compate方法
方法:
add(),remove(),clear().contain(),Iterator迭代器,for()遍历,
List集合:ArrayList <- List <-Collection
有序,可重复,通过
get()获取该位置元素
list1.addAll(2,list2); //在list1的第三个位置插入list2所有元素
list.indexOf("a"); "a"在list中第一次出现的位置下标
list.lastIndexOf("a");"a"在list中最后一次出现的位置下标
remove(); 根据索引或者元素删除该元素
list.set(1,"a");将第二个元素改为a
list.subList(2,4) ; 根据下标位置截取一段元素,形成新的集合,元素包含2,不包含4
list.size() 容量
Vector:老东西,但是线程安全,ArrayList线程不安全,但是还是不推荐。
Map集合:key:value------key不能重复
HashMap:
Map<Integer,Integer> m = new HashMap();
m.put(1,1); //put存储
m.get(1); //get获取
m.remove(1) ; //remove根据key移除
map.size() //长度
map.containsKey(key);
map.containsKey(Value); //判断是否包含key或Value
遍历1:
Set<Object> key = map.KeySet();
for(...){...}
遍历2:
Set<Entry<Integer,Integer>> sets = map.entrySet();
for(Entry<Integer,Integer> set : sets){
syso(set.getKey()+":"+set.getValue());
}
HashTable:
方法和HashMap一样,但是是线程安全的,HashMap不安全的。
不能以Null为key,但是HashMap可以。
TreeMap:
支持key的自然排序和定制排序。
Collections类的一些方法:
Collections.sort(list); 升序排序
Collections.reverse(list); 顺序反转
Collections.replaceAll("a","aa"); 新值替换
范型:
枚举:
案例:
enum Season{
SPRING("春天","春暖花开"),
SUMMER("夏天","炎炎夏日"),
AUTUMN("秋天","秋高气爽"),
WINTER("冬天","寒风凛冽");
private final String name;
private final String desc;
private Season(String name , String desc){
this.name = name;
this.desc = desc;
}
public void show(){
syso(this.name+":"+this.desc);
}
}
public class Test{
public static void main(String[] args){
Season spring = Season.SPRING;
spring.show();
}
}
// 每次通过Season.SPRING获取的Searson对象相同,类似单例模式。
// 枚举类也可以继承接口
常用的类型:
--String:
字面量相同时,instanceof不论有几个变量,对象只有一个;
字面量本身就是一个字符串对象。
new String("str") 存在两个对象,使用new就一定创造了一个新的对象,不论字符串的内容是否相同;
不论是 字面量创建还是new String 创建的对象,其中存储的 都是字符串的final char[];
当我们为一个变量赋一个新的“字符串”内容时,一定是变量指向了一个新的字符串,而不是原字符串的内容改变了
--常用方法:
--StringBuffer:可操控字符串对象;(有序的同步),需要排队使用,单线程
--增删改
--StringBulider:同上,父类继承的类都是一样的,(无序的,同时的同步),多个时间,多个对象可以同时使用他
IO流:
File 创建,生成文件/文件夹
File f1 = new File("D:\\TEST\\a.txt");
File f2 = new File("D:/TEST/a.txt");
File f3 = new File("D:\\TEST\\"+"a.txt");
File f4 = new File("D:\\TEST\\"+File.separator+"a.txt");
File f5 = new File("src/day12/test.java"); --相对路径
File类可以操作文件本身,但是不能操作文件内容:
getName() --文件名称,或者当前文件夹名称
getPath() --文件路径,路径new file()时候写的路径,是绝对的就是绝对的,是相对的就是相对的
getAbsolutePath() --文件,文件夹的绝对路径
getAbsoluteFile() --返回一个用当前文件绝对路径构建的file对象
getParent() --获取父级路径
f.renameTo(new File("d:/test/test1.java")); //给文件或文件夹重命名
exit(); --文件或者文件夹是否存在
canRead() --是否可读
canRead() --是否可写
isFile() --判断当前的File对象是不是文件
isDirectory() --判断当前的File对象是不是文件夹。目录
lastModified() --文件最后修改时间
length() --返回文件长度 ,多少字节数,文件大小
createNewFile(); --创建文件
delete(); --删除文件,文件夹
mkdirs() --创建多层目录
list() --返回String数组,当前文件夹下的所有文件夹和文件的名称
listFiles() --返回File数组,当前文件下所有文件夹和文件的File对象
删除目录的递归方法:
IO流:
输入流input,输出流output:
字节流(inputStream outputStream),字符流(reader writer)
重点:
1.文件的字节输入输出流:FileInputStream , FileOutputStream 单位是byte
文件的字符输入输出流:FileReader , FileWriter
2.缓冲的字节流:BufferedInputStream , BufferedOutputStream
缓冲的字符流:BufferedReader , BufferedWriter
3.InputStreamReader 字节转字符输入流 字节 ——>字符
OutputStreamReader 字符转字节输出流 字节 ——>字符
文件字节流:
FileInputStream:
FileInputStream in = new FileInputStream("d:/a.txt");
//定义一个byte数组接受输入的byte
byte[] b = new byte[10];
int len = 0;
// read(byte[]) 返回读到最后一个数据,后一个数据;若是-1则是读取完毕
while((len=in.read(b))!=-1){
syso(new String(b,0,len));
}
in.close() ; // 使用后一定要关闭
FileOutputStream:
// 指定输出路径,若是不存在则创建文件
FileOutputStream out = new FileOutputStream("D:/b.txt");
byte[] b = "abcd".getByte();
out.write(b); //把数据写到内存中
out.flush(); //把内存中的数据刷到硬盘
out.close(); //关闭流
文件复制方法:
字节流非常通用,因为它使用二进制。
文件字符流:
存放数据的临时组数是char[] 其他都一样:
但是字符流只适合操作为字符文档的文件,入txt;
注意:
当路径下有相同文件是,写入一个文件会覆盖原文件。
当路径下没有文件是,读取会异常。
缓冲的字节流:基于计算机与硬盘间操作,相对较慢,速度受到硬盘读写速度制约,所以缓冲流来绕过限制
BufferedInputStream ; BufferedOutputStream
是对FileInputStream ,FileOutputStream的缓冲
缓冲流是基于内存,FileInputStream是基于硬盘的,速度快75000倍:
BufferedInputStream:
FileInputStream in = new FileInputStream("d:/a.txt");
// 把文件字节流放到缓冲字节输入流对象
BufferedInputStream input = new BufferedInputStream(in);
byte[] b = new byte[10];
int len=0;
while((len = input.read(b))!=-1){
syso(new String(b,0,len));
}
input.close(); // 关闭按照倒叙关闭
in.close();
BufferedOutputStream:
FileOutputStream out = new FileOutputStream("D:/b.txt");
BufferedOutputStream output = new BufferedOutputStream(out);
output.write("aaaa".getBytes());
output.flush();
output.close();
out.close();
将文件a内容读取到文件b:
缓冲的字符流:基于计算机与硬盘间操作,相对较慢,速度受到硬盘读写速度制约,所以缓冲流来绕过限制
BufferedReader ; BufferedWriter 是对FileReader ,FileWriter的缓冲
和上面类似,是char[] 为中间件:
转换流:
字节输入流 -> 字符输入流
FileInputStream in = new FileInputStream("d:/a.txt");
// 设置和读取的编码规则要一致,不然会出现乱码
InputStreamReader reader = new InputStreamReader(in , "GBK"); //传流并定义编码
char[] c = new char[1024];
int len = 0 ;
while((len = reader.read(c))!=-1){
syso(new String(c,0,len));
}
reader.close();
in.close()
字节输出流 -> 字符输出流
FileOutputStream out = new FileOutputStream("D:/b.txt");
OutputStreamWriter writer = new OutputStreamWriter(out , "UTF-8");
writer.write("你好");
writer.flush();
writer.close();
out.close();
标准的输入流输出流:
System.in ;
System.out ;
// 创建一个接受键盘输入数据的输入流
InputStreamReader in = new InputStreamReader(System.in);
// 把输入流放到缓冲流里:
BufferedReader read = new BufferedReader(in);
// 假如数据是String类型
String s=read.readLine();
read.close();
in.close();
对象流:
1.计算机存储是二进制;
2.网络通信也是二进制;
3.就是说要将对象转换成二进制数据流,通过网络进行传输
序列化:Serialize:用ObjectOutputStream类讲一个Java对象写入IO流中
反序列化:Deserialize:从IO流中恢复对象
随机读取流:RandAccess... 从文件某个位置开始读取seek(i)
JDBC: java DataBase Connectvity;java 数据库连接
一系列接口的定义,是访问数据库的标准接口;数据库是由不同的厂家提供的,具体的实现是不同的。具体的数据库厂家按照这个接口来实现,这样对不同的数据库操作就统一了。
--API:
主要包含在java.sql和javax.sql包当中
--接口,流程:
0.加载数据库的驱动driver DriverManager类
1.连接到sql; connection接口,连接对象
2.向数据库发送语句(执行语句) statement接口(PreparedStatement子接口,CallableStatement子接口)语句对象;
3.处理返回结果 ResultSet接口,接口集对象;
4.释放连接;
em:
Driver driver=null; //声明一个driver
driver = new OracleDriver(); //导入OracleDriver中的OracleDriver()方法,实现接口
String url="jdbc:oracle:thin:@127.0.0.1:1521/xe";
String user="test";
String password="test";
Connection conn=null;
Statement stm=null;
ResultSet rst=null;
try {
DriverManager.registerDriver(driver); //驱动管理,驱动注册
conn=DriverManager.getConnection(url, user, password); //注册完后,传参数
stm=conn.createStatement();//连接对象,创建语句对象
rst=stm.executeQuery("select * from t_kinds");
// rst=stm.getResultSet();
ResultSetMetaData md=rst.getMetaData();//元数据对象:对象的对象.去除数据
int colCount=md.getColumnCount();
网络编程:
1.首先了解下协议部分:
TCP/IP协议组,可分为三个层次:网络层、传输层和应用层。
1.网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
2.传输层中有TCP协议与UDP协议。
3.应用层有FTP、HTTP、TELNET、SMTP、DNS等协议。
因此,HTTP本身就是一个协议,是从Web服务器传输超文本到本地浏览器的传送协议。
2.HTTP:
建立连接和关闭连接:
三次握手,四次挥手
3.ServerSocket 和 Socket :
Socket 类 :socket可以使一个应用从网络中读取和写入数据,不同计算机上的两个应用可以通过连接发送和接受字节流,
当发送消息时,你需要知道对方的ip和端口,在java中,socket指的是java.net.Socket类
以public Socket(String host, int port)为例,host为远程机器名称或ip地址,port为端口号。
若连接本地的Server,其端口号为8080,可以写成如下格式
new Socket(“localhost”, 8080);
一旦成功创建一个Socket类的实例,可以用它来发送和接收字节流,发送时调用getOutputStream方法
获取一个java.io.OutputStream对象,接收远程对象发送来的信息可以调用getInputStream方法来返回一个
java.io.InputStream对象。
ServerSocket类 : ServerSocket负责接收客户连接请求,并生成与客户端连接的Socket。ServerSocket与Socket不同,
ServerSocket是等待客户端的请求,一旦获得一个连接请求,就创建一个Socket示例来与客户端进行通信。
ServerSocker构造有多种重载方式:
ServerSocket serverSocket=new ServerSocket(8080);
ServerSocket serverSocket = new ServerSocket(port,3);
把连接请求队列的长度设为 3。这意味着当队列中有了 3 个连接请求时,如果 Client 再请求
连接,就会被 Server拒绝,因为服务器队列已经满了。我们使用的 serverSocket.accept()方法
总之:
客户端向服务器发送请求可分为以下步骤:
1.创建一个Socket实例
2.利用I/O流与服务器进行通信
3.关闭socket
服务器接收客户端请求步骤:
1.创建一个ServerSocket实例,监听客户端发来的请求。
2.与客户端获取连接后,创建一个Socket实例,利用I/O流与客户端进行通信,完毕后关闭Socket。
4.Url类: 该类用来处理有关URL的内容。对于URL类的创建和使用,下面分别进行介绍。
URL可以分为如下几个部分。protocol://host:port/path?query#fragment
protocol(协议)可以是 HTTP、HTTPS、FTP 和 File,port 为端口号,path为文件路径及文件名。
URL url = new URL("http://www.runoob.com/index.html?language=cn#j2se");
System.out.println("URL 为:" + url.toString());
System.out.println("协议为:" + url.getProtocol());
System.out.println("验证信息:" + url.getAuthority());
System.out.println("文件名及请求参数:" + url.getFile());
System.out.println("主机名:" + url.getHost());
System.out.println("路径:" + url.getPath());
System.out.println("端口:" + url.getPort());
System.out.println("默认端口:" + url.getDefaultPort());
System.out.println("请求参数:" + url.getQuery());
System.out.println("定位位置:" + url.getRef());
也可以用url访问网页,获取html文件,http/https都可以:
URL url = new URL("https://www.baidu.com");
try {
//通过URL的openStrean方法获取URL对象所表示的自愿字节输入流
InputStream is = url.openStream();
InputStreamReader isr = new InputStreamReader(is,"utf-8");
//为字符输入流添加缓冲
BufferedReader br = new BufferedReader(isr);
String data = br.readLine();//读取数据
while (data!=null){//循环读取数据
System.out.println(data);//输出数据
data = br.readLine();
}
br.close();
isr.close();
is.close();
反射机制:
1. 什么是反射机制?
首先大家应该先了解两个概念,编译期和运行期,编译期就是编译器帮你把源代码翻译成机器能识别的代码,
比如编译器把java代码编译成jvm识别的字节码文件,而运行期指的是将可执行文件交给操作系统去执行,JAVA反射机制是
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属
性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
2. java反射机制提供了什么功能?
1.在运行时能够判断任意一个对象所属的类
2.运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法
4.在运行时调用任一对象的方法
5.在运行时创建新类对象
getCalss();后的一些列操作
线程:
--实现方式:
继承Thread类,实现Runnable,Callable 接口。重写run方法,后start();
--守护线程:
t.getState(); //获取当前线程装填:RUNNABLE,TERMINATED,NEW,TIMED_WAIT,BLOCKED
t.setDaemon(true); //设置为影子线程(守护线程)
String name=current.getName(); 线程的名字
--背景线程:
t.getState(); //获取当前线程装填:RUNNABLE,TERMINATED,NEW,TIMED_WAIT,BLOCKED
t.setDaemon(true); //设置为影子线程(守护线程)
--同步方法,一个执行,另一个必须等它执行完才能执行该方法:synchronized
--线程状态:
(1)新建状态:即单纯地创建一个线程,创建线程有三种方式,在我的博客:线程的创建,可以自行查看!
(2)就绪状态:在创建了线程之后,调用Thread类的start()方法来启动一个线程,即表示线程进入就绪状态!
(3)运行状态:当线程获得CPU时间,线程才从就绪状态进入到运行状态!
(4)阻塞状态:线程进入运行状态后,可能由于多种原因让线程进入阻塞状态,如:调用sleep()方法让线程睡眠,
调用wait()方法让线程等待,调用join()方法、suspend()方法(它现已被弃用!)以及阻塞式IO方法。
(5)死亡状态:run()方法的正常退出就让线程进入到死亡状态,还有当一个异常未被捕获而终止了run()方法的执行
也将进入到死亡状态!
--死锁:
定义:死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,
它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务。
死锁的发生必须满足以下四个条件:
互斥条件:一个资源每次只能被一个进程使用。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
解决:避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,
规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
--synchronized:监视器锁;
同步的原因是为了防止同一个账号的混乱;
synchronized(this){
同步方法内容(锁的内容)
}
账号加锁;--课后完善
账号优化;--课后完善
--volatile:
volatile boolean loop=false; //重新加载后,其他线程调用会使用加载后的数值
--等待与通知:
wait :1.释放对象的监视器锁;
2.休眠; --wait要释放监视器锁,而sleep并不释放,其他线程无法再进入;
notify :notifyAll()-通知所有的,激活;notify()通知优先级高的那个;
--线程池:
/*可缓冲的线程池*/
ExecutorService pool1=Executors.newCachedThreadPool();
/*定长的线程池*/
ExecutorService pool2=Executors.newFixedThreadPool(4);
/*定时线程池,3代表线程数*/
ScheduledExecutorService pool3=Executors.newScheduledThreadPool(3);
/*单线程池*/
ExecutorService pool4=Executors.newSingleThreadExecutor();
for(int i=1;i<=100;i++) {
pool4.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
pool4.shutdown();
日期类型:
1.date:
Date设置年月日时等方法是过时的,建议使用Calendar对象操作
Date now=new Date(); --现在时间
Data d=new Date(00,0,1); --创建一个时间 1900年1月1号00:00:00
d=new Date(System.currentTimeMillis());====内部英文版本的日期--内部放long值指定日期对象
int year=d.getYear();
2.Calendar :
Calendar.getInstance()方法,获得对象实例
Calendar.geTime()返回Date类型对象
日期格式化:
--SimpleDateFormat:可以new,指定样式;
SimpleDateFormat fmt=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
Date now =new Data();
String str=fmt.format(now); --格式完成
Data d=fmt.parse(str);
--DateFormat:这个类不能new,是抽象类,但是有些静态方法;
getDataInstance(),getDataTime()静态方法和获取实例;
23种设计模式:用于面向对象的设计模式
单例模式:
设计模式:解决问题的思考方式;
单例:只要一个实例,实例化对象;(只会new 一次)
使用环境:实例化消耗大量时间资源;
懒汉式:(用的时候才声明)
private Single(){} //构造私有化
private static Single single = null;
public static Single getInst(){ //只能通过共有的getInst()获取实例
if(single==null){
single = new Single();
}
return single;
}
饿汉式:(可能会浪费空间)
private Single(){} //构造私有化
private static Single single = new Single();
public static Single getInst(){ //只能通过共有的getInst()获取实例
return single;
}
懒汉饿汉区别就是什么时候new这个对象。
缺点1:单线程有用,多线程会有问题,即高并发会有时候不声明,需要进阶(双重检测): --DCL懒汉模式
private Single(){} //构造私有化
private static Single single = null;
public static Single getInst(){ //只能通过共有的getInst()获取实例
if(single==null){
synchronized(Single.class){ // 锁住这个类 --阻塞式同步
if(single==null){
single = new Single();
}
}
}
return single;
}
缺点2:不是与原子性操作:1.分配内存空间,2.执行构造方法,初始化对象,3.把这个对象指向这个空间
会出现指令重排现象。132顺序会出现,则多线程时会出现指令重排。
为了安全:private volatile static Single single = null;
/* volatile就可以说是java虚拟机提供的最轻量级的同步机制.用以声明变量的值可能随时
会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,
主存中值的更新会使缓存中的值失效(非volatile变量不具备这样的特性,
非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可
能读到的并不是是线程A更新后的值)。volatile会禁止指令重排。*/
// 原子性,可见性,有序性是并发的三大特征,所谓原子性,就是一个操作要么全部执行,要么都不执行。
炫技时刻:静态内部类实现 --还是不安全的,因为反射机制(只要有反射,都是纸老虎)
public class Holder {
private Holder() {}
public static class InnerClass{
private static final Holder holder = new Holder();
}
public static Holder getInstance() {
return InnerClass.holder;
}
}
反射来破坏单例:
Constructor<Holder> con = Holder.class.getDeclaredConstructor(null);
con.setAccessible(true); //无视私有
Holder holder = con.newInstance();
反抗:
private Single(){
synchronized(Sigle.class){ //此时已经升级为三级检测锁
if(single!=null){
thow RuntimeException("不要试图使用反射破坏异常");
}
}
} //构造私有化
反射-反抗:
Holder holder1 = con.newInstance();
Holder holder2 = con.newInstance(); // 同时用反射创建对象
反抗2:
private static boolean qingjiang=false; // 使用红绿灯
private Single(){
synchronized(Sigle.class){ //此时已经升级为三级检测锁
if(qingjiang == false){
qingjiang=true;
}else{
thow RuntimeException("不要试图使用反射破坏异常");
}
}
} //构造私有化
反射-反抗2:
Field qinjiang = Holder.class.getDeclaredField("qingjiang");
qinjiang.setAccessible(true);
Constructor<Holder> con = Holder.class.getDeclaredConstructor(null);
con.setAccessible(true); //无视私有
Holder holder1 = con.newInstance();
qinjiang.set(holder1,false);
Holder holder2 = con.newInstance();
道高一尺魔高一丈,这时候只能通过源码分析:
显示Cannot reflectively create enum objects:
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance() {
return INSTANCE;
}
}
class Test{
public static void main(String[] args) {
EnumSingle instance1 = EnumSingle.INSTANCE;
EnumSingle instance2 = EnumSingle.INSTANCE;
System.out.println(instance1);
System.out.println(instance2);
}
}
枚举class反编译分析:
javap -p EnumSingle.class --enmu类型就会被反编译为java文件
也可以使用jad 反编译,显示class extends Enum{}
工厂模式:
1)还没有工厂时代:假如还没有工业革命,如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用。
2)简单工厂模式:后来出现工业革命。用户不用去创建宝马车。因为客户有一个工厂来帮他创建宝马.想要什么车,这个工厂就可以建。
比如想要320i系列车。工厂就创建这个系列的车。即工厂可以创建产品。
3)工厂方法模式时代:为了满足客户,宝马车系列越来越多,如320i,523i,30li等系列一个工厂无法创建所有的宝马系列。
于是由单独分出来多个具体的工厂。每个具体工厂创建一种系列。即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象。
你需要指定某个具体的工厂才能生产车出来。
4)抽象工厂模式时代:随着客户的要求越来越高,宝马车必须配置空调。于是这个工厂开始生产宝马车和需要的空调。
最终是客户只要对宝马的销售员说:我要523i空调车,销售员就直接给他523i空调车了。而不用自己去创建523i空调车宝马车.
这就是工厂模式。
核心:创建者和调用者分离
1.简单工厂模式:(Simple Factory)
产品类:
abstract class BMW {
public BMW(){
}
}
public class BMW320 extends BMW {
public BMW320() {
System.out.println("制造-->BMW320");
}
}
public class BMW523 extends BMW{
public BMW523(){
System.out.println("制造-->BMW523");
}
工厂类:
public class Factory {
public BMW createBMW(int type) {
switch (type) {
case 320:
return new BMW320();
case 523:
return new BMW523();
default:
break;
}
return null;
}
简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。
它存在的目的很简单:定义一个用于创建对象的接口。
先来看看它的组成:
1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。
因为每增加一种新型车,都要在工厂类中增加相应的创建业务逻辑(createBMW(int type)方法需要新增case),
这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。
我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这
些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员。
于是工厂方法模式作为救世主出现了。 工厂类定义成了接口,而每新增的车种类型,就增加该车种类型对应工厂类的实现,这样
工厂的设计就可以扩展了,而不必去修改原来的代码。
2.工厂方法模式:(Factory Method)
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压
力可以由工厂方法模式里不同的工厂子类来分担。
创建工厂类:
interface FactoryBMW {
BMW createBMW();
}
public class FactoryBMW320 implements FactoryBMW{
@Override
public BMW320 createBMW() {
return new BMW320();
}
}
public class FactoryBMW523 implements FactoryBMW {
@Override
public BMW523 createBMW() {
return new BMW523();
}
}
工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口,但使得对象的
数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。
3.抽象工厂模式:(Abstract Factory)
产品类:
//发动机以及型号
public interface Engine {
}
public class EngineA extends Engine{
public EngineA(){
System.out.println("制造-->EngineA");
}
}
public class EngineBextends Engine{
public EngineB(){
System.out.println("制造-->EngineB");
}
}
//空调以及型号
public interface Aircondition {
}
public class AirconditionA extends Aircondition{
public AirconditionA(){
System.out.println("制造-->AirconditionA");
}
}
public class AirconditionB extends Aircondition{
public AirconditionB(){
System.out.println("制造-->AirconditionB");
}
}
创建工厂类:
//创建工厂的接口
public interface AbstractFactory {
//制造发动机
public Engine createEngine();
//制造空调
public Aircondition createAircondition();
}
//为宝马320系列生产配件
public class FactoryBMW320 implements AbstractFactory{
@Override
public Engine createEngine() {
return new EngineA();
}
@Override
public Aircondition createAircondition() {
return new AirconditionA();
}
}
//宝马523系列
public class FactoryBMW523 implements AbstractFactory {
@Override
public Engine createEngine() {
return new EngineB();
}
@Override
public Aircondition createAircondition() {
return new AirconditionB();
}
}
客户:
public class Customer {
public static void main(String[] args){
//生产宝马320系列配件
FactoryBMW320 factoryBMW320 = new FactoryBMW320();
factoryBMW320.createEngine();
factoryBMW320.createAircondition();
//生产宝马523系列配件
FactoryBMW523 factoryBMW523 = new FactoryBMW523();
factoryBMW320.createEngine();
factoryBMW320.createAircondition();
}
}
总结:
无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终
目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨
不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结
构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工
厂方法模式。
所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。
建造者模式:创建型模式
实现构建和表示分离,解耦!
原型模式:也是创造者模式--创造对象
克隆技术,以某一对象为原型,创建出新的对象,提升效率。
Object类中提供了一种方法,从内存中拷贝
方式:
1.创建A类,实现Cloneable 接口,重写clone()方法; --调用的是native本地的c++方法
2.创建B类实现克隆,可以先声明一个A类v1,然后克隆v2=v1.clone(); 这时v1和v2的数值相同,但是hashcode不同,所以克隆出来内容是一样的,但是不是一个对象;
3.上面是浅克隆,因为V1中属性对象假如Date类型,V2也指向了Date,改变v1的date v2也会改变,也就是说v1和v2公用Date;
4.深克隆:序列化和反序列化可以实现(IO,但是效率降低),但是也可以改造克隆方法:
--前:
@Override
protected Object clone() throw CloneNotSupportedException{
return super.clone();
}
--后:
@Override
protected Object clone() throw CloneNotSupportedException{
Object o = super.clone();
Video v = (Video) o;
v.createTime = (Date) this.createTime.clone(); // 把该对象的属性也克隆
return o;
}
适配器模式:--结构型模式(用来松耦合) GUI、SpringBoot用的多
em:电脑和电源中间的适配器
方式:
1.继承,适配器类继承网线; --直接就是无线网卡类似,不用声明网线了;
2.组合,适配器类加网线的类声明为一个属性; --高效的,电脑要先插适配,适配接网线;
桥接模式:--结构型模式 当一个场景中有两个变化的维度例如品牌和类型,便抽象出来 --类似java多平台特点,jdbc绑定不同的数据库
1.品牌通过接口,实现多个品牌的具体类;
2.电脑抽象类,组合品牌,再写出电脑的类型的实体类,通过继承抽象电脑类;
3.测试:声明品牌,再用品牌实现具体电脑类
1.类似多继承方案,但是多继承违背了单一原则,复用差,类的个数也多,所以桥接模式减少子类,降低了管理和维护成本
2、可扩展性,符合开闭原则;
1.增加系统的理解和设计难度;
2.方位有局限性,条件是有两个以上维度;
代理模式:静态,动态,cglib动态代理 ;
AOP: --公司代码
3.行为型模式:
例如:观察者模式:
对象之间多对一依赖的一种设计方案,被依赖的对象为如气象站,依赖对象如新浪等网站,气象站通知众多网站变化。
传统设计方案:无法在运行时动态添加第三方,违反ocp原则
观察者方案:不用修改weathdate等气象站类,添加观察者即可,实现ocp原则
JDK中Observable类就是用了观察者模式:
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable(){obs = new Vector<>();}
...
}
public interface Observer{
void update(Observable o , Objcet arg);
}
OOP七大原则:
1.开闭原则:对扩展开放,对修改关闭,独立扩展
2.里氏替换原则,继承父类尽量添加新的方法,而不是改变父类的方法。正方形不是长方形
3.依赖倒置原则:要面向接口编程,不要面向实现编程,降低耦合性;
4.单一职责原则:单一功能原则,一个方法实现一个功能,实现原子性,解耦,提高内聚性
5.接口隔离原则:各个类建立他们需要的专门接口
6.迪米特法则:只与你的直接朋友交谈,不和陌生人说话 --降低耦合,但是会产生一些中介类
7.合成复合原则:尽量先使用组合或者聚合等关联关系来实现,其次再考虑继承关系来实现;
数据结构进阶(二叉树):
为什么要学习:如TreeMap,TreeSet,Linux的虚拟内存管理,数据库系统等;
树的定义:是由n个节点组成的具有层次关系的集合;
特点规则:
每一个根最多两个节点,且左节点<根节点<右节点(二叉排序树);
结构分析:
每一个节点有三部分构成,left|Date|Right
代码实现添加,查找,遍历:
E:\code\New-computer\newdemo
–3/15:
spring框架:
–10/21视频:
一站式轻量级开源框架,
以ioc,aop为内核没提供了展示层springMVC 和持久层SpringJDBC 众多企业级应用技术
–IOC:控制反转,后提出DI(注入):让调用类对某一接口实现类的依赖关系由第三方(容器或协作类)注入,
以移除调用者对某一接口实现的依赖。
–构造函数注入
--属性注入
--接口注入
--工厂模式注入
--注解方式注入:(只能注入一个,多余的话只能通过xml文件注入)
java.txt --1471
面试题:
1.Bean的生命周期:
在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,
也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Singleton
模式产生单一实例,对单线程的程序说并不会有什么问题,但对于多线程的程序,
就必须注意安全(Thread-safe)的议题,防止多个线程同时存取共享资源所引发的数据不同步问题。
然而在spring中 可以设定每次从BeanFactory或ApplicationContext指定别名并取得Bean时都产生
一个新的实例:例如:
在spring中,singleton属性默认是true,只有设定为false,
则每次指定别名取得的Bean时都会产生一个新的实例
一个Bean从创建到销毁,如果是用BeanFactory来生成,管理Bean的话,
会经历几个执行阶段(如图1.1):
。。。。
在说明前可以思考一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;
1、实例化一个Bean--也就是我们常说的new;
2、按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;
3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;
注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
2.Bean的作用域:
scope:数值的四种,默认singleton
<bean id="..." class="..." scope="singleton">
1.singleton 单例作用域:如果一个 bean 的作用域被声明为 singleton,那么 Spring IoC 容器将只创建一个该对象的实例,并将其存储在缓存中。每次请求该 bean 时,都会返回该缓存对象。Singleton 作用域是所有 bean 的默认作用域。
2.request 请求作用域:该作用域只在 Spring ApplicationContext 的上下文中有效。如果一个 bean 的作用域被声明为 request,就表示其只在此次请求内有效。
3.session 会议作用域:该作用域只在 Spring ApplicationContext 的上下文中有效。如果一个 bean 的作用域被声明为 session,就表示其只在此次会话(session)内有效。
4.prototype 原型作用域:如果一个 bean 的作用域被声明为 prototype,那么每次请求该 bean 时,Spring IoC 都会返回一个新的实例。
--AOP
java.txt --1582
到这里,我们已经全部介绍完Spring AOP。回到开篇的问题,我们拿它做什么?
1.Spring声明式事务管理配置:请参考博主的另一篇文章:分布式系统架构实战 demo:SSM+Dubbo
2.Controller层的参数校验:参考 Spring AOP拦截Controller做参数校验
3.使用 Spring AOP 实现 MySQL 数据库读写分离案例分析
4.在执行方法前,判断是否具有权限
5.对部分函数的调用进行日志记录:监控部分重要函数,若抛出指定的异常,可以以短信或邮件方式通知相关人员。
6.信息过滤,页面转发等等功能
–
springMVC框架
–
spring Cloud: