javaSE笔记

方法重载:
一、想一个方法,先两明确:1.返回值类型 2.参数列表
二、方法重载:在同一个类中,方法名相同,参数列表不同,与返回值无关
JVM会根据不同的参数列表调用不同的方法,就想Math.max()函数。

面向对象:
面向对象开发:
就是不断创建对象,指挥对象
面向对象设计:
就是管理个维护对象之间的关系

类:
定义一个类,就是定义:1.成员变量2.成员方法
这对应显示世界中的属性和行为

对象内存图:
方法区存放:class文件
栈:调用的方法,main方法,对象右边
堆:new出来的对象

成员变量和局部变量:
成员变量:堆中,随对象创建和销毁
局部变量:栈中,随方法创建销毁
它们的初始值不同

形式参数:
基本类型:形式参数的改变不影响实际参数
引用类型:形式参数的改变导致实际参数的改变

匿名对象:
使用场景:仅仅调用一次时使用
好处是匿名对象调用完后就是垃圾,被垃圾回收器回收
匿名对象可以作为实际参数传递:
new Student().show();
new Strdent().show(); 创建了两个不同的对象

封装:
s.age = -27; 这样是不合理的,不能让用户入侵数据内部
应该在赋值之前,对数据进行判断

private int age;
	private只能在本类中用,demo类不能用
封装原则:
	1.把不需要对外提供的内容都隐藏起来
	2.把属性隐藏,提供 public 方法对类访问

this关键字:
this是当前类的对象引用,谁调用这个方法就在该方法内部的this就代表那个对象

构造方法:
系统默认提供一个无参的构造方法
构造方法的作用:对数据进行初始化
构造方法也可以重载
给成员赋值有两种方法
1,setXxx()
2.构造方法

创建对象发生了什么:
Student s = new Student();
1:把Student.class文件加载到内存
2:在栈内存为s变量开辟一个空间
3:在堆内存为申请空间(new)
4:给成员变量进行默认初始化 null或0
5:给成员变量进行显式初始化(如果有直接 =的赋值)
6:通过构造方法给成员变量进行初始化
7:数据初始化完毕,然后把堆内存中的地址值赋值给栈中的s变量

static关键字:
静态的东西是给所有对象共享的
static的特点:
1:随着类的加载而加载
回想main方法
2:优先于对象存在
3:被类的所有对象共享
其实这特点也在告诉我们应该什么时候使用静态?
如果某个成员变量是被所有对象共享的,那么它就应该被定义为静态的
4:可以通过类名调用
其实他本身也可以通过对象名调用
推荐使用类名调用
静态修饰的内容已被称为:与类相关的,类成员

static的内存图:
方法区里专门有一个静态区
堆中的new来的对象有一个静态标记指向静态区

static的注意事项:
1:在静态方法中是没有this关键字的
因为:静态是随着类的加载而加载的,this是随对象的创建而存在的
静态先比对象存在,只能是后面访问前面诞生的
2:静态方法只能访问静态的成员变量和静态的成员方法

静态变量的成员变量的区别
所属不同:
静态变量属于类,也称为类变量
成员变量属于对象,所以被称为实例变量
内存中位置不同:
静态变量存储于方法区的静态区
实例变量存储于堆内存中
内存出现时间不同:
静态变量随着类的加载而加载,同样一起销毁
实例变量与对象生命周期一样
调用不同:
静态变量可以用类名调用,也可以对象调用
实例变量只能用对象名调用

代码块:
局部代码块:局部位置,用于限定变量的什么周期
构造代码块:在类的成员位置,用{}扩起来的代码
无论构造代码块在构造方法前还是后,都先执行!
作用:可以把多个构造方法中的共同代码放在一起
静态代码块:static{}修饰的代码块
作用:一般是对类进行初始化

执行顺序:
	静态代码块----构造代码块----构造方法
	静态只执行一次------构造代码块每次调用构造方法都执行一次

继承
如果有多个类中有相同的属性和方法,将这些内容定义为父类
有了继承以后,我们定义一个类的时候,可以在已经存在的类的基础上,还可以定义自己的新成员

1:Java只支持单继承,但是支持多层继承(继承体系)

继承的注意事项:
1:子类只能继承父类的非私有成员(变量和方法)
2:能继承public方法访问私有,这也体现了继承的弊端,打破了封装性
3:不要为了部分功能而继承
4:子类不能继承父类的构造方法,但是可以通过super关键字去访问父类的构造方法

类中的成员:
成员变量
构造方法
成员方法

继承中成员变量的关系:
	A:子类中变量不同名(太简单)
	B: 变量名一样呢?
		在子类方法中访问一个变量的顺序:
			1:方法局部范围中找
			2:子类中成员范围找,有就使用
			3:在父类的成员范围找,有就用
			4:都找不到就报错

问题:
我想要输出局部范围内的num,也要本类的num,也要父类的num?
num----this.num----super.num

super的关键字
this代表本类的引用
super代表 父类存储空间的标识

怎么用?

继承中构造方法的关系
A:子类中所有的构造方法默认都会访问父类中无参构造方法
不论有参还是无参都会用到父类的无参构造方法
B:为什么呢?
因为子类会继承父类中的数据,可能还会使用父类的数据,所以子类初始化之前,一定要先完成父类数据的初始化
每一个构造方法的第一条语句默认都是super();

分层初始化:先进行父类初始化,然后进行子类初始化

继承中成员方法的关系:
A:名字不同,太简单
B:名字相同呢?
1:先找子类
2:再找父类
3:没就报错

方法重写override:子类中出现了和父类方法声明一模一样的方法

方法重载overload:本类中出现的方法名一样,参数列表不同,与返回值无关,
方法重载能改变返回值类型,

override的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样既沿袭了父类的功能,又定义了子类特有的内容

问题:智能手机类覆盖了功能机的方法,能玩游戏但不能打电话,怎么解决
	用super.call();

方法重写的注意事项:
1:父类私有方法不能覆盖
2:子类重写父类方法是,访问权限不能更低
最好就一致

final关键字:
由于继承方法中有方法重写,所以父类的功能会被子类覆盖掉
有些时候我们不想让子类覆盖掉父类的功能

final常可以修饰类
	最终类不能被继承,通常最底层的类用final,不让它能继承了
final可以修饰方法
	该方法不能被重写
final可以修饰变量
	该变量不能被重新赋值,因为这个变量其实就是常量
常量:
	A:字面值常量
		“hello”,10,true
	B:自定义常量
		final int x = 10;

final修饰变量的初始化时机
A:被final修饰的变量只能赋值一次
B:在构造方法完毕前

多态的前提:
要有继承关系
要有方法重写
要有父类引用指向子类对象
父 f = new 子();

多态中成员访问特点:
	A:成员变量
		编译看左边,运行看左边。
	B:构造方法:子类的构造都会默认访问父类构造
		创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
	C:成员方法
		编译看左边,运行看右边。
		因为方法存在覆盖,所以父类方法被覆盖掉了
	D:静态方法
		编译看左边,运行看左边
		静态和类相关,算不上重写

	结论:有与成员存在方法重写,所以它运行看右边

自己解释:
因为变量是内在描述
方法是外在表现
父类引用指向子类对象,变量值是父类,难道创建了父类对象吗?没有!!!
栈:Fu f
堆:子类对象(this-----,super--)
方法区:----class文件区-----常量区--------方法区-------

多态的好处:
A:提高了代码的维护性---有继承保证
B:提高了代码的扩展性---由多态保证

多态的弊端:
FU f = new Zi();
f.ziFun();
父不能使用子类的特有功能
现象:
子可以当父使用,父不能当子使用

	A:创建子类对象
		Zi z = new Zi();
		可以,但是太占内存
	B:把父类的引用强制转换为子类的引用(专业名词:向下转型)
		Zi z = (Zi)f;

问题1:
动物---->狗 可以!
动物---->猫 可以!
动物---->猫---->狗 编译时不报错,运行时报错!
//ClassCastException 类转换异常
问题2:
Father f = new Son();
f.子类特有();
会报错吗?会,在编译时出错
//找不到符号

抽象类:
#把多个共性的东西提取到一个类中,这是继承的做法
但是呢,这多个共性的东西,在有些时候
方法声明一样,但是在每个具体的对象在实现的时候内容不一样
所以,在定义这些共性的方法的时候,就不能给出具体的方法体
而一个没有具体的方法体的方法是抽象的方法
如果一个类中如果有抽象方法,改类必须定义为抽象类

A:抽象类和抽象方法必须用abstract修饰
	抽象类中不一定有抽象方法,但是有抽象方法一定是抽象类
B:public abstract void eat(){有东西}//会报错,
	有抽象方法的类必须定义为抽象类
C:抽象类不能实例化
	因为它不是具体的
	抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?
		用于子类访问父类数据的初始化
D:抽象的子类
	如果不想重写抽象方法,该子类是一个抽象类
	重写所有的抽象方法,这个时候子类是一个具体的类
E:抽象类的实例化其实是靠具体的子类实现的,是多态的方式
	Animal a = new Cat();

多态最主要的应用是在抽象之间,对外界提供的是抽象类,真正靠具体东西实现

抽象类的成员特点
1、成员变量:既可以是变量,也可以是常量
2、构造方法:有,用于子类访问父类数据的初始化
3、成员方法:里面的方法既可以是抽象的,也可以是非抽象的

抽象类的成员方法特性:
	抽象方法:强制要求子类做得事情。
	非抽象方法:子类继承的事情,提高代码复用性。

抽象类的几个小问题
一、一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
可以,为了不让创建对象

二、抽象类不能和哪些关键字共存:
	private 冲突
		抽象类就是为了让你重写,private都继承不了了,怎么重写
	final 冲突
		最终不能被重写
	static 无意义
		可以通过类名。方法调用,但是抽象方法是没有方法体的,调用了有什么意义呢?

接口
#额外的功能,java提供了接口表示

接口不能实例化
	接口按照多态的方式来实例化(向上转型)
由此可见:
接口的子类
	可以是抽象类,但是意义不大
	具体类实现接口
		要重写接口中所有的抽象方法(推荐方案)	

接口的成员特点(和抽象类的区别)
成员变量:
接中的变量默认是final,也是static
默认修饰符:public static final
建议:自己手动给出
构造方法:接口没有构造方法
因为接口主要是扩展功能的,而没有具体存在
成员方法:
接口方法必须是抽象的 默认是public的
接口的默认方法是public abstract
最好自己写

类与类
继承关系,单继承
类与接口
实现关系,可以但实现,多实现
接口与接口:
接口可以单继承,可以多继承
类是单继承 接口是多继承

如果实现了多个接口要注意,对应的接口要对应的方法

抽象类和接口的区别
A:成员区别
B:关系区别
C:设计理念区别
抽象类:被继承体现的是:is a 的关系 抽象类中定义的是该继承体系的共性功能
接口:被实现体现的是: like a 的关系 接口中定义的是该继承体系的扩展功能。 (将来的功能)

可以看day9总结
总结:
多态
(1)同一个对象在不同时刻表现出来的状态
(2)多态的前提:
A:有继承或实现关系
B:有方法重写
C:有父类或者父接口引用指向子类对象
(3)多态的分类:
A:具体类多态
B:抽象类多态
C:接口多态

形式参数和返回值的问题
形势参数:
基本类型(太简单)
引用类型
类:(匿名对象讲过了)
抽象类:
#抽象类没有具体类是用不了的,所以,我们应该先定义一个具体类
#孔子装爹
Person p = new Student();
接口:
需要该接口的实现类对象
返回值:
基本类型:PASS
引用类型:
类:返回的是该类的对象
抽象类:
接口:

类的修饰符
:权限修饰符:默认、public
状态修饰符:final
抽象修饰符:abstarct

内部类:
#把类定义在其他类的内部
访问特点:
1:内部类可以直接访问外部类的成员,包括私有
2:外部类访问内部类的成员,必须创建对象
内部类位置:
成员位置:在成员位置定义的类
局部位置:在局部位置定义的类
访问方法:
Outer.Inner oi = new Outer().new Inner();

 匿名内部类:
 	#内部类的简化写法
 	前提:存在一个类或接口,可以是具体类也可以的抽象类
 	格式:
 		new 类或接口名() {  @重写方法 }

 	本质:
 		本质不是一个类而是一个对象
 		#只有子类或者具体类
 		是一个继承了该类或者实现了该接口的子类匿名对象
 	使用方法:
 		#本质是对象
 		匿名对象只能调用一次方法
 		改进方法:
 			多态 Inter i = new(){ @重写}

Object
每个类都直接或间接继承
1:hashCode()
返回该对象的哈希码值,不是地址值,将根据哈希算法计算出来的值
2:gerClass()
返回此Objext的运行时类
2.1Class类的方法:getName以String的形势返回此Class的对象锁便是的类
3:toString()
返回该对象的字符串便是
重写最终方案:自动生成toString方法
4:equals()
#指示其他某个对象是否与此对象“相等”
A:== 等于号
基本类型:比较的就是值是否相等
引用类型:比较的就是地址值是否相等
B:equals
源码: return( this == obj)
默认时候比较的是地址值,一般来说意义不大 我们要重写能?
怎么重写?
一般都是用来比较对象的成员变量值是否相等;
#String的equals方法是重写值Object类的,比较的是字符串的内容是否相等
# 对象名 instanof 类名:判断该对象名是不是该类的一个对象
引用类型:默认情况下,比较的是地址值
不过,我们可以根据情况自己重写该方法,一般重写都是自动生成,比较对象的成员变量值

5:finalize()
	当垃圾回收器确定不存在该对象的更多引用时,有对象的垃圾回收器调用此方法,用于垃圾回收,但是什么时候回收不确定
6:clone()
	创建并返回此对象的一个副本
	可以实现对象的克隆,包括成员变量的数据复制,但是他和两个引用指向同一个对象是由区别的
	finalize和clone都是protected的
	A:重写该方法
	Cloneable:
		这个接口是标记接口,告诉我们实现接口的就可以实现对象的复制了

Scanner类
#用于获取用户的键盘输入
A:导包 import java.util.Sacnner
B:创建对象 Scanner sc = new Scanner(System.in
system类下有一个静态的字段
public static final InputStream in;标准输入流 对应着键盘输入
其实就是一个InputStream类变量
C:调用方法

基本方法
public int nextInt();
public String nextLine();

String类
字符串就是由多个字符组成的
A:字符串字面值可以看成一个字符串对象
B:字符串是常量,一旦被赋值就不能被改变
String s = "hello"
s += "world"
Sop(s)
为什么输出的是helloworld 不是不可以改变吗?
字符串直接赋值的方式是先到字符串常量池里找,没有就创建兵返回
栈:String s
堆:
方法区:1:字符串常量池:hello 2:world 3:helloworld
!:值不能变 但是引用能变

String类重写了equals 比较的是内容相同
String s1 = new String("hello");
String s2 = "hello";
== false
equals true
解释:
s1的情况:栈里String s1----堆里new string--->指向常量池hello
s2的情况:栈里String s2---->发现常量池里有hello
虽然值是一样的,但是s1指向堆里的对象,对象再指向hello,s2直接指向hello,地址是不一样的
区别:前者创建两个对象,后者创建一个对象

字符串如果是变量相加,先开空间,再拼接
字符串如果是常量相加,是先加,在在常量池里找,找到就返回,没找到就创建

StringBuffer
我们对字符串进行拼接,每次拼接都会构建一个新的String对象
StringBuffer可以解决这个问题
线程安全的可变字符串

StringBuffer与String的区别:
前者长度和内容可变
字符串拼接,不会浪费资源
构造方法:
public StringBuffer(); 无参构造方法
public StringBuffer(int capacity);指定容量的字符串缓冲区对象
public StringBuffer(String str);指定字符串内容的。。
StringBuffer的方法:
public int capacity();返回当前容量 理论值
public int length();返回长度(字符数) 实际值
使用方法:
StringBuffer sb = new StringBuffer();
//创建了字符串缓冲区对象

StringBuffer的添加功能:
//public StringBuufer append(String str);//记住他的返回类型是StringBuffer 型
StringBuufer sb2 = sb.append("hello");
相当于sb返回到sb2,所以他是不浪费空间的,没有开辟新空间

#一步一步添加
sb.append("hello");
sb.append(12);
sb.append(562345);
sb.append(1);
#链式编程
sb.append("hello").append(576457).append(4567).append(33);

String和StringBuffer的相互转换
我们为什么要讲解类之间的装换:
A --> B的转换
我们把A转换成B,其实是为了使用B的功能
B --> A
我们可能要的结果是A类型,所以还得转回来

注意:不能把字符串的字直接赋值给StringBuffer
方式1:
	通过构造方法
	String s = "hello";
	StringBuffer sb = new StringBuffer(s);
方式2:
	通过append()方法
	StringBuffer sb2 = new StringBuffer();
	sb2.append(s);

StringBuffer转回String
StringBuffer buffer = new StringBuffer("java");
方式1:
	通过构造方法
	String str1 =new String(buffer);
方式2:
	通过toString方法
	String str2 = buffer.toString();//任何引用类型调用toString()方法都能转成字符串String类型

字符串反转:

StringBuffer的面试题:
了解一下StringBuilder:
一个可变的字符序列,此类提供一个与StringBuffer兼容的API,但不保证同步(不同步说明不安全,说明效率高)

1:String, StringBuffer, StringBuilder的区别
	A:String是内容不可变得,。。。是可变的
	B:StringBuffer是同步的,安全:StringBuilder是不同步,不安全,但效率高

2:StringBuffer和数组的区别
	二者都是容器,装其他的数据
	StringBuffer的数据最终的一个字符串数据
	数组是同一类型的数据,自己定义类型

3:String和StringBuffer作为参数传递:(形式参数问题)
	String:
	因为字符串是常量值
	所以字符串是一个特殊的引用类型,可以把它当做基本类型来看
	所以形参改变对本身没有影响,它拿的是hello的值来用的!不是地址值!
	把String当成常量看就行了!

	StringBuffer:
	直接复制传递不到外面
	还是调用方法可以传递到外面 append。。。。。

冒泡排序:
相邻元素两两比较,大的

Arrays工具类的使用
针对数组进行操作的工具类
A:public static String toString(int[] a);
B:public static void sort(int[] a); 底层是快速排序
C:public staric int binarySearch(); 二分查找

使用:
int[] arr = {......};
sop( Array.toString(arr) );

基本类型包装类
需求1:把100以二进制,八进制,16进制计算出来
需求2:判断一个数据是否在int范围内
首先你要知道int范围是多大的?

	//public static String toBinaryString(int i);
System.out.println(Integer.toBinartString(100));
	//public static String toOctalString(int i);
	//public static String toHexString(int i);

	//public static final int MAX_VALUE;
	//public static final int MIN_VALUE;
	SOP(Integer.MAX_VALUE)

类有成员方法,有成员变量,所以我们把它看成类才调用方便
为了对基本数据类型进行更多的操作。Java就针对每一种基本数据类型提供了对应的类类型

常见的操作:用于基本数据类型于字符串之间的装换

Integer的构造方法:
public Integer(int value);
public Integer(String s)
使用方法:
	int i = 100;
	Integer ii = new Integer(i);
	String s = "100";
	Integer iii = new Integer(s);

int类型和String类型的转换
int -- String
String -- int

方法1:
int number = 100;
String s1 = "" + number;

方法2:
String s2 = String.valueOf(number);
最好的方法,静态方法,类名直接调用

方法3:
Integer i = new Integer(number);
String s3 = i.toString();

方式4:
String s4 = Intrger.toString(number);

//String -- int
String s = "100";
Integer.parseInt(s);

自动装箱和拆箱
//定义了一个int类型的包装类型变量i
Integer i = new Integer(100);
这不是int类型哦,这是Integer类型

Integer ii = 100;//ii是引用类型
				//这可以直接赋值?可以
ii += 200;//本来应该报错的,因为一个引用类型不可以加int类型
ii += 200;
System.out.println("ii:" + ii);
自动装箱:把基本类型转换为包装类类型
自动拆箱:把包装类类型转换为基本类型

通过反编译之后的代码:
Integer ii = Integer.valueOf(100);//自动装箱
ii = Integer.valueOf(ii.valueOf() + 200);//先自动拆箱,再自动装箱
System.out.println( ( new StringBuilder("ii:") ).append(ii).toString());

Integer直接赋值的面试题:
	通过查看源码,我们知道了,针对-128~127的数据,做了一个数据缓冲池,
	如果数据是该范围内的,每次并不创建新的空间
	所以地址值是相同的,equals也相同
	so:
		Integer的数据直接赋值,——128到127之间,会直接从缓冲池里获取数据

集合框架
为了方便对多个对象进行操作,我们必须对多个对象进行存储
要想存储多个对象,就不能是一个基本的变量,而应该是一个容器类的变量
数组和集合的区别
1:长度区别
数组的长度固定
集合长度可变
2:内容不同
数组同一类型
集合可以不同类型
3:元素的数据类型
集合只能存储引用类型
视频:集合的继承体系图解

Collection:是集合的顶层接口
功能:
添加功能:
boolean add(Object obj)
addAll

	删除功能:
		clear:移除所有元素
	判断功能:
		contains:
		containsAll(collection c)
	获取功能:
	长度功能:
	交集功能:

测试:
//创建集合对象
Collection c = new Collection();
报错!为什么?因为接口不能实例化啊

ArrayList是实现类

Collection c = new ArrayList();
//这个集合放元素永远能成功,因为返回的都是true
#测试基本功能
c.add("hello");
c.add("world");
c.clear();//移除所有元素
c.remove("hello");
c.contains("hello");//判断有没有这个
c.isEmpty();
c.size();//元素个数,hello world 就是两个
#高级功能
//创建集合1

//创建集合2

集合的遍历
其实就是依次获取集合的每一个元素

Object[] toArray():把集合转成数组,可以实现集合的遍历

Collection c = new ArrayList();
c.add.....
...
Object[] objs = c.toArray();

for{
	//向下转型
	String s = (String)objs[x];
}

Collection存储自定义对象并遍历

Conllection c = new ArrayList();
//创建学生对象
Student s1 = new Student("dxxxx");
.....

//把学生添加到集合
c.add(s1);
...

//把集合转成数组
Object[] objs = c.toArray();
//遍历数组
for:
	print(objs[x]);//这个不行,打印出来的是地址值
	//转型
	Student s = (Student)objs[x];
	print(s.getName().....)

迭代器
原理:
Object next():获取元素,并移动到下一个位置
NoSuchElementException:没有这个元素异常,因为已经找到最后了
boolean hasNext():如果仍有元素可以迭代,
用法:
Collection c = new ArrayList();
c.add(xx)
....
Iterator it = c.iterator();
while(it.haxNext()){
String s = (String)it.next();
print(s);
}
迭代器,是遍历集合的一种方式
迭代器式依赖于集合而存在的(所以说先有集合再有迭代器)
问题:迭代器为什么不定义成一个类,而是一个接口?
java中提供了很多的集合类,每个集合类的数据结构是不同的,所以存储方式和遍历方式都是不一样的
如果定义一个类,就是一个具体实现
而无论是哪种集合,都应该具备获取元素的操作并辅助于判断功能,这样在获取前,更不容易出错;也就是说,判断功能和获取功能应该是一个集合遍历所具备的,而每个集合的数据结构不同,所以我们把这两个功能提取出来,并不提供具体实现,这种方式就是接口。
那么,真正具体的实现类在哪里呢?
在真正的具体的子类中,以内部类的方式实现。
源码:
class ArrayList下有内部类
private class Itr implement Iterator{};
所以当:
Iterator it = c.iterator();//是return Itr();

List集合存储字符串并遍历
List是接口

List list = new ArrayList();
list.add("hello");
.....
Iteretor...

List:有序(存储和取出的元素一致),可重复的
//public interface List extends Collection

1:有序的collection
2:可以对列表中的每个元素插入位置进行精确控制
3:可以根据整数索引访问元素
4:与set不同,列表通常允许重复的元素

List的特有功能:
A:添加功能
void add(int index,E element):在指定位置添加元素
B:获取功能
Object get(int index):获取指定位置的元素
C:列表迭代器
ListIterator listItertor():List集合特有的迭代器
D:删除功能
Object remove(int index):根据索引删除元素,返回被删除的元素
E:修改功能
Object set(int index,Object element):根据索引修改元素,并返回

用法:
List list = ArryList();
不用迭代器的方法
for:x < list.size();
String s = (String)list.get(x);
//用size()和get()结合

列表迭代器:
ListIterator listIterator(): List特有的迭代器
改迭代器继承了Iterator迭代器,可以用hesNext。。。。

特有功能:
Object previous()
boolean hasPrevious()

List的子类特点
ArrayList(:
底层数据结构是数组,查询快,增删慢
线程不安全,效率高
Vector:
底层数据结构是数组,查询快,增删慢
是同步的
LinkList:
底层数据结构是双向链表
线程不安全,效率高
查询多用Array,增删多用Link、

LinkedList的特有功能
A:public void addFirst(Object e);
public coid addLast();

B:public object getFirst();

C:public E removeFirst();

LinkedList list = new LikedList();

link.addFirst("zero");//会在一堆元素放在前面

去除重复的元素
思路1:创建一个新集合,遍历旧集合
if(!newArray.contains(s))
newArray.add(s);
思路2:不创建新集合的方法
拿0索引的元素依次和后面的比较,有就remove()

自己模拟一个集合类,实现栈的数据
public class MyStack{
private LinkedList link;

public MyStack(){
	link = new LinkedList();
}

public coid add(Object obj){
	link.addFirst(obj);//问题:这个link是什么?不是局部变量吗?
}

public Object get(){
	// return link.getFirsrt();
	// 每次都是弹出来第一个,不行
	return link.removeFirst();

}

public boolean isEmpty(){
	return link.isEmpty();
}

}

泛型
为什么要泛型?
array.add(10)//会报错吗?因为只能存储引用类型,不会!因为自动装箱了
//等价于array.add(Integer.valueOf(10))
集合也模仿数据这种做法,在创建对象时明确数据类型,就好了

泛型:是一种吧类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型,也叫:参数化类型
ArrayList<String> array = new ArrayList<String>();
array.add(10)//报错了
这样:
Iterator<String> it = array.Interator();
...
String s = it.next();//这样就不用强制转换了

好处:
	把运行时的问题提前到了编译期间
	避免了强制转换
	避免黄色警戒线
泛型在那些地方使用呢?
	一般来说在集合中使用
泛型推断
	//。。。 = new ArrayList<>();
	不建议使用
	还是
	ArrayList<String> array = new ArrayList<String>();

类加载器和反射,动态代理
类的加载
#当程序要使用某个类的时候,如果该类还未加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化
加载:
就是将class文件读入内存中,并为之创建一个Class对象
任何类被使用时系统都会建立一个Class对象
连接
1:验证 是否有正确的内部结构,并和其他类协调一致
2:准备 负责为类的静态成员分配内存,并设置默认初始化值
3:解析 将类的二进制数据中的符号引用替换为直接引用
初始化
就是以前的初始化

类初始化时机
创建类的实力
访问类的静态变量,
调用类的静态方法
反射方式
初始化某个类的子类
java.exe

类加载器
类加载器的组成
Bootstrap ClassLoader 根类加载器
负责加载Java核心类的加载
Extension ClassLoader 扩展类加载器
System ClassLoader 系统类加载器
负责在JVM启动时加载来java命令的文件

反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制

反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法

要想这样使用,首先要得到class文件对象,其实也就是得到Class类的对象
Class类:
成员变量: Field
构造方法:Constructor
成员方法:Method

获取class文件对象的方式:
A:Object类的getClass()方法
Person p = new Person();
Class c = p.getClass();

B:数据类型的静态属性class
	Class c = Person.class;
	int.class;
	String.class;

C:Class类中的静态方法
	Class c = Class.forName(#全路径的类名)//要有包名

通过反射获取构造方法
//获取字节码文件对象(都要干的事)
Class c = class.forName("xxx.Person");这里可以通过xml来配置
//获取构造方法
//public Constrctor[] getConstructors();返回的是所有的公共构造方法,所以是数组
Constructor[] cons = c.getConstrutors();

获取单个构造方法
Constructor con = c.getConstructor();	返回的是构造方法对象
Object obj = con.newInstance();
print(obj);
相当于!:
	Person p = new Person();
	pritnt(p);
	但是反射是不会让你看到这个的
	xml里的是谁,就是谁

步骤:获取字节码对象--通过字节码对象获取构造器对象--通过构造器对象来创建一个对象

通过反射获取带参构造方法
。。。。。

通过反射获取成员变量
Class c = Class.forName("xxx");
获取单个的成员变量
获取address并赋值
相当于要实现的:
Person p = new Person();
p.address = "北京";

先通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();

Field addressField = c.getField("address");
//public void set(Object obj,Object value);
//将指定对象变量上此Field对象表示字段设置为指定的新值
addressField.set(obj,"北京");//给obj对象的addressField字段设置为“北京”;
给A对象的B字段赋值为C,xml中配置


通过xml文件,就能设置不同的字段
以前是p.address
现在是c.getField("adress")//想填什么字段都可以

通过反射获取成员方法

面向对象设计原则
单一职责原则
高内聚低耦合
每个类应该只有一个职责,对外提供一种功能,而引起类变化应该只有一个
所有的设计原则都遵循这一原则
开闭原则
一个对象对扩展开放,对修改关闭
对类的改动通过增加代码进行,而不是修改现有代码
借助抽象和多态
里式替换
在任何父类出现的地方都可以用他的子类代替
也就是说,同一个继承体系中的对象应该有共同的行为特征
依赖注入原则
要依赖于抽象,而不是依赖于具体实现
接口分离原则
一个接口不需要提供太多的行为,只提供一种功能

设计模式的分类
创建型模式:对象的创建
结构型模式:对象的组成
行为型: 对象的功能
创建型模式
1:简单工厂模式:
又叫静态工厂方法模式,负责创建一些类的实例
//有了工厂后,通过工厂创建
2:工厂方法模式:
抽象工厂类负责定义创建对象的接口
具体对象的创建工作由继承抽象工厂的具体类实现
需要增加一个具体的类和具体的工厂类
3:单例设计模式
单例模式要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供
如何保证类在内存中只有一个对象呢?
A:把构造方法私有
private Student(){}
B:在成员位置自己创建一个对象
Q为什么要要静态?类初始化的时候就创建,只有一个了
1:饿汉式:一进来就造对象
private static Student s = new Student()
2:懒汉式:
private static Teacher t = null
C:通过一个公共的方法提供访问
饿:public static Student gerStudent(){return s}
懒:if(t==null){t = new Teacher()}
//第一次时造
单例模式的思想是什么?
开发:饿汉式(不会出问题的
面试:懒汉式
public synchronized static Teacher gerTeacher(){
if (t == null){
t = new Teacher();
}
return t;
}

代表JVM运行环境的Runtime类

JDBC
导jar包:驱动!
加载驱动类:ClassForName("类名")
给出url,username,password url要背下来
使用DriverManager类来得到Connection对象!

void fun(){

	jdbc四大配置参数
	>driververClassName:com.mysql.jdbc.Driver
	> url : jdbc:mysql://localhost:3306/mydb
	> username:root
	> password : 666666

	//可能出错:ClassNotFoundException
		> 没导包,找不到类
	Class.forName("com.mysql.jdbc.Driver");//加载驱动类(注册驱动)
	加载一个类,会执行这个类的静态代码块

	String url = "jdbc:mysql:localhost:3306/mydb";
	String username = "root";
	String password = 666666;

	//DriverManager.getConnection需要三个参数,会返回一个连接

	//使用url用户和密码得到连接对象

	//可能出现SQLException:
		> 检查3个参数时候正确
		> 是否开始了mysql服务器
	Connection con = DriverManager.getConnection(url, username, password);
	sout(con);

}

JDBC原理

应用---->JDBC---->MYSQL驱动---->Mysql
			 |
			 |-->Oracle驱动---->Oracle

连接不同数据库的区别就在去这四大参数的区别

Driver源码:
	public class Driver extends.. implements java.sql.Driver //任何驱动类都要实现这个接口
	staric里:
		java.sql.DriverManager.registerDriver(new Driver());
	所有的java.sql.Driver实现类中,都提供了static块,块内的代码就是把自己注册到DriverMannager中


一、连接数据的
	得到connection就算成功!
二、对数据库增删改
	1:通过Connection对象创建Statement
		> Statement:语句的发送器,他的功能是向数据库发送sql语句!
	2:调用它的int executeUpdate(String sql),它可以发送DML DDL

	Statement stmt = con.createStatement();
	String sql = "INSERT INTO stu VALUES();

	int r = stmt.executeUpdate(sql);
	sout(r);
	//返回 1

三、执行查询(区别是不会对数据库进行更改)
	public void chaXun(){
		一、得到Connection
		二、得到Statement,发送select语句
		三、对查询返回的"表格"进行解析!

		//四大参数
		String driverClassName = "com.mysql.jdbc.Driver";
		String url = "jdbc:mysql://localhost:3306/xxx";
		String username
		String password

		//加载驱动类
		Class.forName(driverClassName);

		//get连接
		Connection con = DriverManager.getConnection(url,username,password);

		//得到Statement
		Statement stmt = con.createrStetement();

		//发送sql
		//ResultSet rs = executeQuery(String )

		ResultSet rs = stmt.executeQuery("select * from xxx");

		//解析ResultSet
		//ResultSet有一个行光标
		//ResultSet的next()方法可以把光标向下移动
		//next()返回的布尔值,表示当前行时候存在

		if(rs.next()){ //把光标向下移动一行,并判断下一行时候存在
			int id = rs.getInt(1);
			int name = re.getString("name");
			//通过列编号可以 通过列名也可以
			sout(id + "," + name);
		}

		//改成while循环
		whilr(rs.next()){ //指向最后一行就返回false
			int id = rs.getInt(1);
			int name = re.getString("name");
			sout(id + "," + name);
		}

		//最后都要关闭
		//关闭资源
		rs.close();
		stmt.close();
		con.close();// 这个必须关闭

	}

	代码规范化
	在try外给出引用的定义
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
	在try内为对象实例化
	在finall中关闭

	public void fun3(){		
		Connection con = null;//引用放在外边
		Statement stmt = null;
		ResultSet rs = null;
		try{
			一、得到连接
			String driverClassName = "com.mysql.jdbc.Driver";
			String url = "jdbc:mysql://loacahost:3306/xxx";
			String username = "root";
			String password = "666666";

			Class.forName(driverClassName);
			con = DriverManager.getConnection(url,username,password);

			二、创建statement
			stmt = con.createStatement();
			String sql = "select * from xxx";
			rs = stmt.executeQuery(sql);

			三、循环遍历rs,打印
			//getString()和getObject()几乎是通用的

			while(rs.next()){
				sout(xxx);
			}
			}catch(Exception e){
				throw new RuntimeException(e)
				}finally{
			//关闭
			//有可能出现空指针异常,为了保证代码的健壮性,执行关闭之前判断一下是否为空
					if(rs != null) rs.close();
					if(stmt != null) stmt.close();
					if(conn != null) conn.close();
				}
	}

Statement的重要方法

int executeUpdate(String sql):执行更新操作,即执行insert,update,delete语句,其实这个方法也可以执行create table等等语句,但我们很少会使用JDBC来执行这些语句

ResultSet executeQuery(String sql):来执行查询操作,执行查询操作会返回ResultSet,即结果集

boolean execute();
可以执行executeUpdate()和executeQuery()两个方法一样,但是返回的是该sql语句时候成功
还需要调用其他方法来获取

结果集的特性:当使用Connection的createStatement时,已经确定了Statement生成的结果集是什么特性
是否可滚动
是否敏感
是否可更新

PreparedStatement
它是Statement接口的子接口
功能:
防止SQL攻击
提高代码的可读性,可维护性
提高效率

用法:

posted on 2021-02-21 22:10  兔哥DB  阅读(61)  评论(0编辑  收藏  举报

导航