Java1-35 Java学习笔记

day1

win7 192.168.218.171
win10 192.168.218.204

内网通文件目录:C:\Users\Public\Nwt\cache\recv
Eclipse:C:\Users\Administrator\workspace
因为下载Notepad++而出来的垃圾安装包:C:\Users\Administrator\AppData\Local\Temp\gzss

环境配置

环境变量 下面(系统变量)新建名字:JAVA_HOME变量值为jdk安装位置
新建名CLASSPATH变量值为:.
打开path在变量名最后加:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin

第一个Java:Hello

先编译javac后解释java的语言(Java)

变量

整形(bype:1字符,short:2字符,int:4字符,long:8字符),浮点型,字符型(char:2字符),布尔型(boolean:true false)
引用数据类型:类(字符串),接口,枚举,数组

自动转换(没有缺点)
强制转换(有缺点 如long转成int会产生精度损失)

要求:
1: 熟记JDK,JRE,JVM之间的关系
2: 熟记Java的数据类型,并能全部手写出来
3: 熟记变量的使用
4: 数据数据类型之间的转换,明白什么是自动转换,什么是强制转换

day2

1.final修饰的变量是常量,值不可以改变 final int m;
2.%取余
3.i += 50 为 i = i + 50
4.byte b = 5;
b = b + 5会报错 因为5是int类型
5.
i=5
if(i++)判断时先使用i(判断i)后自增
if(++i)判断时先自增后使用(判断i)i
6.字符串链接符 +
7.
常量池中的数据只有一份
可用new来开辟堆中的空间
8.str.equals(str1)判断字符是否相等,字符判断不可用==
9.逻辑运算符 &&(短路与)与&(位与) A&&B A为false时B不执行
A&B不管A为什么B也会执行 ||与|同理

day3

字符串转换为int

Integer.parseInt();string型字符串转换为int

day4

尽量不要使用while(true){}

Switch()可以使用嵌套

Switch()case里面如果没有break程序会继续向下面进行直至遇见break或者结束。

需要用到if()时简单的都可以用三目运算符替代A条件D?C:B;

Math.random()* n 生成0到n的数字(为小数)

day5

Arrays:是JRE提供给我们的一个工具类,专门用于操作数组的,里面提供了很多与数组有关的方法。
* Arrays.toString(array): 可以将数组转化成字符串。
* Arrays.sort(array); 可以将数组的元素进行升序排序。
* Arrays.binarySearch(array, 487); 返回元素在数组中的下标位置,如果是负数代表不存在,二分查找,需要有序。
* Arrays.fill(array,555); 将数组内的元素都变成555
* Arrays.copyOf(array, 10); 复制一个新的数组,长度为10,并且在有效长度之内新数组的值与老数组相同
* Arrays.copyOfRange(array, 2, 10);从下标2开始拷贝,到下标10截止,将内容复制到新数组中,长度不够用默认值补。
* Arrays.equals(copyOfRange, copyOfRange2) 对比数组中的值是否相等。

day6

昨日内容回顾:
1: while循环以及do while的区别,以及使用
2: 数组的动态实例化以及静态实例化,数组的使用
3: Arrays工具类的使用
4:冒泡排序以及选择排序

今天内容:

1:类与对象

今天早上我去吃饭,我遇到一个人请问我遇到的是谁?如果这样去问,大家肯定不知道我遇到了谁,
因为人这个概念太模糊了,如果我说今天早上我去吃饭我遇到了关思思,大家知道我遇到谁了么?
此时人这个概念被具体化成了关思思,这样大家都知道我遇到的是谁了。
人:
属性:性别,年龄,身高,体重
行为:吃饭,睡觉,说话
如果只是说人的话,那么人虽然有所有的属性以及行为,但是这些属性基本上都没有具体的值。

关思思:
属性:女,18,158,80
行为:吃饭,睡觉,说话
但是如果我们根据人的这个模板生成了一个具体的对象,就可以给这个对象赋值了。

猫:年龄,颜色,品种,名字
tom:81, 蓝色,短毛猫,汤姆

类:是一个非常抽象的概念,我们没有办法指着类去说它具体是指谁,因为类指向的是一个大体,类
里面抽离了所有实例对象的共有特征形成了属性,而在类中这些属性是没有具体值的,因为这些属性
虽然写在类中,但是属性具体的值却属于通过类实例化出来的对象。

对象:通过类创建出来的实例(对象就是类的实例化体现),类是比较抽象的概念,而对象却是一个具体的
概念,每个对象都有自己的属性,与其他对象无关。

我们可以简单理解成:
类是一个设计图纸,这个设计图纸上虽然标注的有形状,样子,等很多属性,但是在图纸上并不是真实存在
的,如果我们通过设计图作出了真正的产品,那么产品的值就是真实存在在的。

一:类主要是由属性(变量),方法,代码块组成。

变量的划分:

全局变量

​ 1:直接声明在类中,其作用域是整个类。
​ 2:全局变量是由默认初始值的(不需要初始化也可以直接使用)。
全局变量有两种
​ 1:被static修饰的变量,存储在常量池之中,被所有对象共享,并且可以直接通过类名调用。
​ 2:没有static修饰的变量,存储在堆内存中,每个对象都有自己的一份,不会共享,只能通过
​ 对象名.调用。

局部变量

​ 1: 一般声明在方法之内,作用域一般都是声明时候的作用域,例如如果直接声明在方法中,作用域
​ 就是整个方法,如果声明在方法体中的for循环作用域里,变量的作用域就只是这个for循环。
​ 2: 局部变量没有默认初始值,这就是说局部变量必须初始化之后才能使用。

static

什么时候使用static修饰变量?

1:由于static修饰的变量在内存中只有一份,只要有任何一个对象修改了就都会被修改,所以我们
一般会在static变量前面加上final,让其禁止修改。
2:只有在工具类中,定义某些方便使用,但是又不需要被改变值的变量,才会使用staticfinal定义,
例如Math类中的PI常量等。

方法

1:实际上方法就是指,将一些功能性代码封装起来,方便以后反复使用。
2:我们的所有代码都在一起,看起来会非常凌乱,如果我们将每段代码都封装成一个方法,这样代码
看起来就会方便很多。
例子: 如果没有方法的话,每次我们使用冒泡排序都需要写一堆排序的代码,用10次要写10次,非常
麻烦,但是如果我们将排序的代码封装成一个方法,那么以后当我们需要排序的时候直接调用方法
就可以了,不需要在重复写排序的代码了。

方法的语法: [] 代表可选
[访问修饰符] [static] 返回值类型 方法名([形参列表…]){
方法体
}

访问修饰符

主要用来控制方法可以被哪些类访问到。
1:public 公交车,谁都能乘坐。 代表本项目中所有的类都能使用这个方法。
2:protected校车,只有校内能乘坐。 代表本包下所有类,以及其他包下的子类对象能使用这个方法。
3:无 专线车 代表本包下所有类都能使用这个方法。
4:private 私家车 代表只有本类中能访问到这个方法。

返回值类型

决定的是,当方法执行完成后返回给调用者什么类型的数据。
1:当我们写方法的时候,想返回给调用者什么数据,就写什么类型即可。
题目:
(1)写一个方法,最后返回长度为4的字母+数字组合的随机验证码。 答:返回值应该是String。
(2)写一个方法,最后返回两个数的乘积。 答:返回值应该是int 或double。
(3)写一个方法,用来返回类中所有属性拼接的信息。 答:返回值应该是String。
(4)写一个方法,这个方法最后会返回一个Dog类对象 答:返回值应该是Dog。

2:如果方法有返回值的话,在方法的最后需要使用return关键字,将数据返回给调用者。
题目:
(1) String str=“随机生成的验证码”;
return str;
(2) int j=ab;
return j; 或者 return a
b;
(3) return “Dog[age=]”+age+",name="+name;
(4) Dog d = new Dog();
return d;

3:如果方法执行之后,不需要返回调用者数据,使用void关键字来表示这个方法没有返回值。
4:如果方法使用了void关键字,就可以不需要return数据了。
5:有返回值的方法,执行完成后会变成对应的数据,我们可以将其放在输出语句之中,或者使用
变量接收方法的返回值。

方法名

​ 标识符之一,自定义的根据命名规则其即可。

四:形参列表 调用方法的时候,需要方法的调用者传递给我们什么值,就写什么。
方法中有时候需要使用一些数据,而这些数据需要方法的调用者传递给我们,此时我们就可以将
这些数据定义在形参列表中。
例如:计算A 与B 的乘积,那么A和B肯定要由方法的调用者传递给我们,我们才能计算,此时就可以
在形参列表上定义A 和B两个变量。
例如:给int数组排序,那么int数组肯定是由方法的调用者传递给我们,我们才能排序,此时我们
形参需要定义一个int数组。

方法体

方法想实现什么功能,就写什么代码。

静态

1:被static修饰的方法,叫静态方法,可以使用类名直接调用,同时也可以被对象调用。
2:被static修饰的方法,无法直接访问实例成员的属性(无static修饰的属性)以及实例方法。
3:没有static的方法,叫实例方法,只能使用对象调用。
4:实例方法可以访问所有的变量以及方法。

构造方法(构造器): 构造方法是专门为了创建对象而存在的。
1: 构造方法没有返回值类型的说法,因为他就是为了创建对象而存在。
2: 因为构造方法必须创建自身类的对象,所以要求构造方法的名称必须与类名一致。
3: 如果类中没有写构造方法的话,会自动生成一个默认的无参构造方法。
4: 构造方法可以重载。
问:构造方法主要的用处是?
答: 主要的用处就是用来给刚创建出来的对象属性进行赋值。

this:当前使用的对象,代码执行到哪个对象的时候,this就代表谁。
1:使用this.属性,可以调用当前对象的属性。
2:使用this.方法(),可以调用当前对象的方法。
3:使用this() 是调用自身的构造方法,需要注意,调用自身的构造方法只能在构造方法中调用。
4:静态方法中没有this,只有实例方法中以及构造方法中才有this的存在。
问:什么情况下使用this
答:当我们方法中的局部变量名与全局变量名冲突的时候,如果想使用全局变量需要使用this关键字。

要求

1: 个人笔记。
2: 代码三遍。
3: 定义工具类MyArrays实现方法如下
3.1: 可以对所有类型的数组进行升序排序
3.2: 可以对所有类型的数组进行降序排序
3.3: 可以将所有类型的数组的数据转化成字符串然后返回
3.4: 可以从所有类型的数组中查询元素是否存在,如果存在返回下标,不存在返回-1

day7

面向对象的三大特征:

一:封装

1: 将一组对象的共有属性以及行为抽象成一个类。
2: 将属性私有化,提供公开的方法来访问属性,方法的要求是: 
2.1 赋值的方法名要set开头后面跟上属性的名字以name举例:setName
	由于要给属性赋值,所以赋值的方法肯定是有参的,无返回值。
2.2 取值的方法名要get开头后面跟上属性的名字以name举例:getName
	由于要取出属性的值,所以取值的方法肯定是有返回值的,并且无参。
3: 将一组功能性代码,封装成方法方便以后反复调用。

二:继承

是指孩子从父辈或者爷爷等祖辈继承下来的一些家产,也就是指孩子可以使用父辈的一些东西,现实中一般人只能继承自己亲生父辈的家产,而现实中每个人都只有一个亲生的父母,也就是
说一般情况下每个人只能继承1次。
Java中的继承是指,子类可以使用extends关键字去指定自己的父类,然后继承父类的非私有属性以及方法。
1: 每个人只有一个爹,所以Java只支持单继承,也就是说我们的类只能继承一个类。
2: 但是每个爹都可能会有很多个孩子,所以每个类都可以被继承多次。
3: 现实中每个人肯定都有父亲,在Java的类中每个类也都有父类,如果我们的类没有指定父类,默认会继承于Object,所以Object类是所有类的超类(基类)。
4: 子类可以从父类继承方法,如果子类对父类的方法功能不满意,可以选择重写父类的方法,如果子类重写了父类的方法,在调用方法的时候会先调用子类的方法实现。
5:  构造方法不能被继承。
6:  **在创建子类对象的时候,JVM会调用父类的无参构造创建父类的实例化对象,然后在去实例化子类对象。**
7:  如果父类没有无参构造,我们需要在子类的构造方法中使用super来显示的调用父类的构造方法。
super:代表了父类对象
super()  	表示调用父类的构造方法
super.属性	表示调用父类的属性
super.方法()	表示调用父类的方法
方法重写:

​ 1: 重写是发生在父子类关系之中的,方法名称需要与父类方法名一致。
​ 2: 形参列表需要与父类一致。
​ 3: 返回值类型需要与父类一致。
​ 4:要求子类的访问修饰符不能比父类更严格。
当我们将对象放入到输出语句的时候,默认会自动调用toString方法,那么我们只要重写toString方法,让toString方法返回对象信息的字符串,就可以实现输出对象的时候直接输出对象
的所有信息。

final关键字:

1:修饰在变量上,让其变成常量。
2:修饰在类上,final修饰的类不能被继承,String就是被final修饰的所以不能被继承。
3:修饰在方法上,final修饰的方法不能被子类重写。

static关键字:

1: static修饰在变量上,变量会变成静态成员,可以被类直接调用。
2: static修饰在方法上,方法会变成静态方法,可以被类直接调用。
3: static修饰在类上,叫做静态类
4: static修饰在代码块,叫做静态块。

代码块:Java中代码块分为4种

1:静态块 直接写在类中,被static修饰的代码块,只有在类第一次被加载的时候会执行一次。
2:构造块 直接写在类中,无任何修饰的代码块,每次创建对象的时候都会执行一次。
3:普通块 写在方法之中,可以避免方法中的变量名冲突,但是同时也局限了变量的作用域。
4:同步块------预留后期多线程时候将
静态块–优先所有–>构造块—优先自身—>构造方法

三:多态

见day11

day9

内部类

day10

接口与抽象类区别

接口中的常量默认被public static final修饰

接口中的实例方法必须被default修饰,default前面默认存在public,并且只能为public。

接口中的静态方法必须是public修饰符

接口中的抽象方法默认被public abstract修饰

/**
 * @author Administrator
 * interface:用来表示这是一个接口
 * class     :用来标识这是个类。
 * 接口和类的区别:
 * 1.接口中只能有常量,而抽象类中可以有成员变量。并且接口中的常量默认被public static final修饰,而抽象类中可以有成员变量。
 * 2.接口中的实例方法必须被default修饰,default前面默认存在public,并且只能为public。而抽象类中实例方法随意。
 * 3.接口中的静态方法必须是public修饰符,而抽象类随意
 * 4.接口中没有构造器,而抽象类中有
 * 5.接口中没有静态块和构造块,而抽象类中全有
 * 6.接口中的抽象方法默认被public abstract修饰,
 * 7.接口是被类用来实现的(普通类实现接口,必须添加所有的抽象方法实现),而抽象类是被用来继承的
 * 8.一个类可以同时实现多个接口,而抽象类只能单继承
 * 9.接口可以多继承接口,而抽象类只能单继承
 *总结:
 *
 *作用:
 *1.主要用来充当方法的目录,统一所有实现类中方法的规范
 *2.在以后的项目中,我们可能会使用很多常量值,如果常量值的定义到处都是的时候很麻烦,此时可以将所有的常量都保存在接口中
 */

day11

三:多态

就是指多个形态。
1:多态是指声明的是父类(包括接口)的类型,但是实例化的却是子类(实现类)的对象。
2:继承或实现+方法的重写是多态的前提条件。
多态的好处:
1:可替换性(Anmial a ;
a= new Pig(); //声明接口类型,实例化实现类的对象。
a= new Cow();
a= new Mouse()
2:可扩充性(我接口或父类新增实现类或子类不影响之前的代码结构)
3:灵活性
4:简化性

多态的缺点:
1:当我们使用多态的时候,只能调用子类重写父类的方法,无法调用子类自身独有的方法。
2:如果需要调用子类自己的方法,需要进行向下转型的操作。
向上转型与向下转型:
所谓的多态就是指引用数据类型的向上转型 ,将子类的实例化向上转成了父类的类型
既然存在向上转型,就同时存在向下转型,向下转型是指将父类的类型强制转成子类的类型,需要注意向下转型要求必须存在父子关系,否则会报类型异常。

Api: 应用程序接口是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。 [1] 用来提供应用程序与开发人员基于某软件或硬件
得以访问的一组例程,而又无需访问源码,或理解内部工作机制的细节。

Api实际上就是一个应用程序的说明书,一个应用程序有很多的方法或功能,而Api就是这些类以及方法的介绍。

Work:
1: 整理什么是多态
2: 将昨天的作业,都改成多态的实现。

下午我们讲30~60分钟API 300~600分钟API:

day12

根据Api练习

String类, StringBuffer , StringBuilder ,Object类,[System类],Math类,Date类,Calendar类,DateFormat类,Byte类,Short类,Integer类,Long类,Float类,Double类,Boolean类,Character类,BigInteger类,BigDecimal类,Arrays类。

day13

String.format         String.split​(String regex)

String  regionMatches()测试两个字符串区域是否相等

String indexof() 返回指定字符第一次出现的字符串内的索引。 
String.join
Byte.toUnsignedInt
Character:digit,   //无用
Dateformat类是时间格式化类,专门用于格式化时间使用
calendar类是日历类,可以单独设置或取出年月日等操作


sc.subSequence(2, 4)返回的是下标23的子序列?
BigDecimal : plus() 舍入
Long reverse
String matches		正则表达式

1toLowerCase(Locale locale) 
将所有在此字符 String ,以降低使用给定的规则情况下 Locale 

4clone()//有可能会将,也有可能不会将。
5System.getproperty与setproperty有什么用,主要用于获取以及设置一些系统属性。

6append(CharSequence s) 追加指定的 CharSequence到这个序列。
7DateForma :  parse(String source) 。 从给定字符串的开始解析文本以生成日期
8notify();唤醒正在等待对象监视器的单个线程。
9notifyAll(); 唤醒正在等待对象监视器的所有线程
10offsetByCodePoints(char[] a, int start, int count, int index, int codePointOffset) 
返回给定的 char子阵列中的索引,该子阵列与 index由 codePointOffset代码点偏移。

ArraysparallelPrefix(double[] array, DoubleBinaryOperator op)
setAll(int[] array, IntUnaryOperator generator)
spliterator(int[] array)
stream(int[] array)
StringBufferint offsetByCodePoints(int index, int codePointOffset) 

int 跟 integer 或charCharacter 这种基本数据类型和复杂数据类型有何区别,
为什么要有复杂数据类型,复杂数据类型的作用以及用在何处。
*************************************异常体系*****************************************
Throwable:  所有异常以及错误体系的顶级父类,其下面有两个子类分别是Error以及Exception

Error: 表示的是错误,一般都是指硬件出现一些问题,或者程序结构出现一些问题,这种错误程序员无法通过
代码捕获,而且一般情况下无法通过代码解决。例如: JVM内存不足,或者程序运行中途断电了,JVM内部出现
问题等各种物理问题。

Exception:表示异常,一个合理的应用程序应该去捕获并且处理异常,异常分为两种1:运行期异常2:编译期异常。
一:运行期异常
在代码编译的过程中,程序不会报错,但是在运行的过程中可能会出现异常情况,例如:
1: 数组下标越界		java.lang.ArrayIndexOutOfBoundsException
2: 算数异常			java.lang.ArithmeticException: / by zero
3: 空指针异常		java.lang.NullPointerException
运行期异常的特点是:当别人调用方法的时候,不会强制让调用者处理异常。

二:编译期异常
编译期异常是指在程序编译的阶段就必须要处理的异常,如果不处理的话就会出现编译错误。
编译期异常的特点是:当别人调用方法的时候,需要强制让调用者处理异常。

异常的处理:
一:try catch捕获处理异常
try{
	写有可能出现异常的代码。
}catch(捕捉的异常类型  对象名){
	处理异常的代码。
}finally{
	无论是否出现异常,这里的代码都会执行。
}

二:在方法体上面使用throws关键字对异常向上抛出,抛给调用者进行处理,如果是在main方法中抛出,会抛给
JVM虚拟机进行自动处理。

为什么要处理异常:
当程序出现异常之后,如果程序员没有捕获异常,那么异常会由JVM虚拟机自动处理,而JVM处理的方式是:
1:打印异常信息 	2:关闭虚拟机。	这样的话会造成程序运行中断,而如果程序员捕获了对应的异常信息,
那么就会由程序员写的catch代码块来处理异常,JVM不在进行插手。


1: 笔记
2:代码5,之前作业完成   
3:知道以后遇到异常如何解决。
4:预习集合

day14

异常处理

为什么要有异常:
异常实际上是一个类似警告牌一样的功能,在方法中合理创建异常对象可以提醒方法调用者需要
注意的内容,以及在方法调用者出现问题的时候可以给与解决提示。

异常的处理流程:
1: 当程序运行过程中出现异常之后,JVM会检测当前出现异常的代码是否存在于try作用域之内
2: 如果代码不在try作用域,JVM会自己捕获异常然后进行处理。
3: JVM处理异常的方式先打印异常的相关信息,然后关闭虚拟机。
4: 如果代码存在于try的作用域,JVM会将异常对象的类型按照catch的书写顺序与所有的catch一个一个进行
比对,如果所有的catch全都匹配不成功,JVM会自己处理异常。
5: 如果catch匹配成功,JVM会将异常对象注入到catch域的形参之中然后执行catch作用域的代码。
6: 当catch作用域代码执行完成后,继续执行finally里面的代码,然后继续往下执行下面的代码。

自定义异常:
RuntimeException:  是所有运行期异常的父类,所有的运行期异常全部都继承于RuntimeException,如果
我们需要自定义运行期异常,只需要继承RuntimeException即可。

Exception:所有异常的父类,其和所有除了RuntimeException的子类都是编译期异常,如果我们需要自定义
编译期异常只需要继承Exception即可。

throw: 用于在方法之内,抛出异常对象给虚拟机,如果想在写方法的时候抛出异常对象必须使用throw才可以,
简单点说,throw就是用来创建异常对象的。

throws:用于方法体之上,将方法可能出现的异常交由方法的调用者进行处理,这个关键字自身不会产生异常
对象,简单点说,throws是一种消极的解决异常的方式。

当我们在写一些方法提供别人使用的时候,可以会用throw去创建一些编译期异常对象,用于提醒方法调用者一些
信息,此时我们需要使用throws将异常交给方法调用者处理,才能让对方注意到。

作为方法,我们有两个角色:
1: 方法的编写者经常使用throw以及throws关键字,来对调用者进行提醒。
2: 方法的调用者经常使用try catch finally来解决编写者抛出的异常。

********************************我是分割线*********************************************

Work:
1: 给所有资料,笔记整理好,从头到尾完整复习一遍,看是否有遗忘以及不连贯的地方。
2: 写一个MyArrayList类,里面有个数组可以存储任何引用数据类型的数据,数组的初始容量是10,每次扩容
1.5倍,然后提供add(添加元素),size(获取长度),set(修改数据),get(根据下标查询数据),remove(删除数据)
等方法,要求自己写的MyArrayList可以使用for循环遍历取值等,尽量模仿Arraylist里面所有的方法,并且
不准查阅资料。
3:写一个单向链表,实现LinkedList的基本方法。
4:写一个人类,属性随意,里面最少有一个银行对象,以及现金对象。
5:写一个银行类,属性随意,要求最少要有账号和密码,以及存款余额三个属性。
6:写(一个或多个)ATM方法,此方法调用需要传入一个人类对象,在方法里面可以无限进行操作(参考现实ATM)。 
7:如果有空的话,可以把之前所有的作业在写一遍。
总体要求:独立实现,不准查阅资料,可以问询同桌等请求帮助。

泛型

通常情况下,我们在类中定义的各个属性,都是直接确定了类型,这个类型在代码程序的运行中是无法改变的,而
这样通常会造成很多硬编码,那么我们可否在类中写一个不确定的数据类型,然后在初始化对象的时候去指定里
面的属性具体是什么类型的,这样的话每次初始化对象都能指定一次,这个技术就叫做泛型。

泛型:将类中属性类型的确定工作推迟到实例化对象的时候来决定。
    先回想一下类中的属性,比如public int a;那么a的属性类型就是int型,当使用类初始化对象one时
那么one.a的属性就是int,无论定义几个对象,a属性的类型都是int。若想要满足一个功能:单链表,由于单链表
里面存储的数据类型(比如单链表1只存储年龄,单链表2只存储姓名),并且单链表只能每个节点存储一个数据,并且
每个单链表所有的数据都是同一种类型的,那么在单链表类中的a的数据类型就是不确定的,只有在声明单链表对象时才
能知道是存储年龄的单链表还是存储姓名的单链表,这时就需要使用泛型了
    
	参考下面的代码,内部类Node后面有泛型的定义形式,那么此内部类里面的属性就可以使用E来声明,这样声
明的优点是:声明属性的时候没有明确的说“声明的属性是int还是string等”。这就说明此内部类的属性是不确定的
可以满足在声明类的对象时定义对象中属性的数据类型
public class MyLinkedList {
	public static void main(String[] args) {
		MyLinkedList myLinkedList = new MyLinkedList<>();
		myLinkedList.add("3452");
		myLinkedList.add("rdrg");
		myLinkedList.add("g6");
		
		String string = myLinkedList.get(1);
		System.out.println(string);
	}
	private int size=0;
	private Node first = new Node();
    
	private static class Node{
		Node next;
		E element;
		public Node() {
		}
	}
    
	public void add(E element){
		Node nod = new Node();
		if (size==0) {
			first.next=nod;
			first.element=element;
			size++;
		}else {
			node(size).next=nod;
			node(size).element=element;
			size++;
		}
	}
	public E get(int index){
		return node(index).element;
	}
	private Node node(int index) {
		Node x =first;
		for (int i = 0; i < index; i++) {
			x=x.next;
		}
		return x;
	}
}

day16

YDemo12

MyArraysList和MyLinkedLink的解说

day17

集合图里面的内容,collection,list,ArrayList等

集合的体系:

Java中的集合总共分为三大类,分别是list,set以及map,其中list与set都是单列集合,map是key-
value的键值对。
名称			类型		作用
Iterable: 	接口		里面封装了一个迭代器对象,以及一个forEach迭代的方法。
Iterator:	接口		迭代器的顶层接口,定义了迭代器的规范。
Collection: 接口		所有单列集合顶级接口,里面定义了所有单列集合共有的功能,并且继承了Iterable的迭代器。
List:		接口		有序可重复的单列集合的顶级接口,里面定义了所有有序单列集合的共有功能,并且继承了Collection。
Set:		接口		无序不重复的单列集合的顶级接口,继承了Collection。
Queue:		接口		队列的顶级接口,继承于Collection。
AbstractCollection	对Collection接口提供了基本的实现。
AbstractList		对list接口的内容提供了基本的实现,同时继承了AbstractCollection

ArrayList:

ArrayList继承于AbstractList继承于AbstractCollection实现了接口Collection

​	集合类,继承于AbstractList,并且实现了List接口。
​	1:底层由数组实现,有序并且值可以重复。
​	2:默认初始容量是10,每次扩容都是1.5倍,可以通过构造方法指定初始容量。
​	3:由于存在下标,所以查询和修改速度较快,但是删除和插入较慢。
​	4:线程不安全,效率较快。

Vector:

Vector继承于AbstractList继承于AbstractCollection实现了接口Collection

​	集合类,继承于AbstractList,并且实现了List接口。
​	1:底层由数组实现,有序并且值可以重复。
​	2:默认初始容量是10,每次扩容都是2倍,可以通过构造方法指定初始容量。
​	3:由于存在下标,所以查询和修改速度较快,但是删除和插入较慢。
​	4:线程安全,效率较慢。

AbstractSequentialList: 继承于AbstractList,定义了一些为链表提供的顺序操作。
Stack: Vector的子类,诞生于JDK1.0,基本没有使用了。


Deque: 是一个双端队列接口,继承于Queue接口。
ArrayDeque: Deque的实现类,是一个双端队列的集合,同时继承了AbstractCollection。

LinkedList:

LinkedList继承于AbstractSequentialList继承于AbstractList继承于AbstractCollection实现了接口Collection

集合类,实现了Deque队列接口以及List接口的同时又继承了AbstractSequentialList。
	1:底层是由双线链表+双端队列实现。
	2:由于链表的底层不存在原生下标,所以查询与修改较慢(没有下标,需要不断遍历),插入和删除较快(没有下标,不需要维护)。

AbstractSet 对set接口的内容提供了基本的实现,同时继承了AbstractCollection以及实现了set接口。

ArraysList与Vector与LinkedList的使用

		ArrayList底层为数组   方便查找修改
		vector底层为数组      方便查找修改
		linklist底层为链表    方便增删
		
		List<String> list = new LinkedList<String>();//Vector<>();//ArrayList(0);
		list.add("张三");
		list.add("李四");
		list.add("王五");           //存储方法.add();
		list.add("赵六");
		list.add("田七");
		list.add("张三");
		list.add(2, "哈哈");
		list.set(5, "啦啦");
		list.remove("王五");

		for (int i = 0; i < list.size(); i++) {		    //list集合遍历方法一
			System.out.print(list.get(i)+"\t");
		}
		for (String string : list) {                	//list集合遍历方法二
			System.out.print(string+"\t");
		}
		Iterator<String> iterator = list.iterator();	//list集合遍历方法三
		while (iterator.hasNext()) {
			System.out.print(iterator.next()+"\t");
		}
		list.forEach(s->System.out.print(s+"\t"));      //list集合遍历方法四
		list.clear();                                   //链表清空
		for (String string : list) {                    //清空后的链表无法打印出来
			System.out.println(string+"566666");
		}

HashSet

HashSet继承于AbstractSet继承于AbstraceCollection实现了接口Collection,HashSet实现了Set接口
集合类,实现了Set接口,同时继承了AbstractSet。
	1: HashSet集合是无序的,并且值不能重复。
	2:HashSet在代码中创建了一个HashMap对象,将值存入到Map的Key上面,所有的操作都是通过HashMap来完成。

SortedSet: 接口 里面定义了一些比较方面相关的内容,想为set提供排序的方法。
NavigableSet接口 完善了SortedSet比较和排序的方法规范,继承了SortedSet。

TreeSet

TreeSet继承于AbstractSet继承于AbstractCollection实现了几口Collection,TreeSet实现了一些接口

集合类,实现了NavigableSet接口,同时继承了AbstractSet。
1:TreeSet集合可以按照我们的书写规则对元素进行排序,值不能重复。		
hashMap如何保证key不重复的。(HahSet如何保证值不重复)
1: 先通过hashCode求出一个数值,如果这个数值跟已有的冲突的话,会调用key的equals方法来判断是否真的出现hash冲突,还是重复
插入。
2: 如果出现了hash冲突则会使用链表形式来存储出现hash冲突的元素。
TreeSet如何进行排序的
1: 需要实现Comparable 接口,然后在里面通过compareTo方法来完成排序,排序的规则为: 返回正数排在后面,返回负数排在前面,
返回0的话TreeSet会认为是相同的对象,造成添加数据失败。

HashSet与TreeSet的使用

HashSet使用的是HashMap里面的方法            底层为哈希表
HashSetTreeSet里面存储的内容不可以重复

public class MySet {
	public static void main(String[] args) {
		/*Set set = new HashSet<>();
		set.add("张三");
		set.add("王五");
		set.add("张三");
		for (String string : set) {
			System.out.println(string);
		}
		Iterator iterator = set.iterator();
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}*/
		
		Set<Dog> set = new HashSet<>();/*new TreeSet<>();*/
		set.add(new Dog("小黄", 3));
		set.add(new Dog("小白", 4));
		set.add(new Dog("小吴", 1));
		set.add(new Dog("小花", 2));
		set.add(new Dog("小吴", 1));
		set.add(new Dog("小吴", 1));
		set.add(new Dog("小吴", 1));
		for (Dog dog : set) {
			System.out.println(dog);
		}
		System.out.println("----------------------------");
		Iterator<Dog> iterator = set.iterator();
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

class Dog implements Comparable<Dog>{
	private String name ;
	private int age ;
	public Dog(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	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;
	}
	@Override
	public String toString() {
		return "Dog [name = "+name+" age = "+age+"]";
	}
	/**
	 * 使用hashset,需要用到其add方法的时候,由于hashset存储的内容是不重复的
	 * 所以需要改变add方法的方法体,由于hashset不可改变,但是其用到了equals
	 * 方法与hashCode方法,且这两个方法属于超类object
	 * 所以可以重写(如下面的,重写了类Dog的equals与hashCode),这样便可以达到
	 * 存储的值(对象)不相同
	 * 对于string类的对象来说不需要重写,因为string类本身已经重写过了equals与 hashCode方法
	 * equals是比较值的,由于对象的属性不止一个,所以需要hashCode
	 * hashCode是根据所有的属性生成一个数字并判断是否相同,由于有hash冲突,所以需要有equals
	 */
	@Override
	public boolean equals(Object obj) {
		if (this==obj) {
			return false;
		}
		if (obj==null) {
			return false;
		}
		if (getClass()!=obj.getClass()) {
			return false;
		}
		Dog d = (Dog) obj;
		if (age!=d.age) {
			return false;
		}
		if (name==null) {
			if (d.name!=null) {
				return false;
			}
		} else if (!name.equals(d.name)) {
			return false;
		}
		return true;
	}
	/**
	 * hashcode方法的唯一目的,就是根据所有的属性的值,计算出来一个数字
	 * 1:所以如果对象的属性一样,生成的数字肯定一致
	 * 2:由于hash冲突的存在,虽然属性的值不同,但是却生成了一样的数字。
	 */
	@Override
	public int hashCode() {
		final int prime=31;//声明局部常量31
		int result=1;//定义记录总数的值
		result = prime*result+age;//根据对象属性的值,求出了一个新的值
		result = prime * result + (name == null ? 0 : name.hashCode());//根据name属性更新了值
		return result;
	}
	@Override
	public int compareTo(Dog o) {
		if (this.age>o.age) {
			return 1;
		}else if (this.age<o.age) {
			return -1;
		}else {
			if (this.name.hashCode()>o.name.hashCode()) {
				return 1;
			}else if (this.name.hashCode()<o.name.hashCode()) {
				return -1;
			}
		}		
		return 0;
	}
	
}

Work:
1:在不考虑源码情况下会使用list,set所有的集合类实现CRUD(增删改查的简写)。
2: 参考Api练习集合类中的对应方法。
3: 熟记ArrayList,LinkedList以及Vector的区别,和底层实现以及继承结构。
4: 了解HashSet与TreeSet的继承结构,记住HahSet如何保证值不重复的,以及TreeSet如何进行排序。

day18

map的实现方法讲解(put,get),map主要使用的是table数组(transient Node[] table)而数组中存在(即内部类Node中存在)链表(链表即类中声明该类本身),即map主要是使用数组和链表实现的。数组用来存储key值和value值,链表也是用来存储key值和value值,但是链表是挂在数组上面的。链表的主要存在原因是因为数组的内容存储时可能会有下标冲突(即由hash算出来的下标已经存储了一个值oldvalue,但是这次计算出来的相同下标的值newvalue与已存在的值oldvalue不同,这时新的值value也需要存储,便可以弄个链表来解决,先声明一个链表头first指向此下标,然后first向下的节点存储这个新的值newvalue)的问题(即hash冲突,内容不同时,计算出来的下标可能相同)。

HashMap

Hashtable与ConcurrentHashMap不可以存空值,HashMap可以——map.put(null, null);

Hashtable与ConcurrentHashMap与HashMap的使用方法,区别等

		底层为数组和链表
		
		//ConcurrentHashMap<>();//Hashtable<>();//HashMap<>();
		Map map = new HashMap<>();
		map.put("key1", 1111);
		map.put("key2", 2222);
		map.put("key3", 3333);
		map.put("key4", 4444);
		//Hashtable与ConcurrentHashMap不可以存空值,HashMap可以
		//map.put(null, null);  
		System.out.println(map.get("key3"));
		map.put("key3", 123);
		System.out.println(map.get("key3"));
		map.remove("key4");
		System.out.println("-------------------");
		System.out.println(map.get("key4"));
		System.out.println("-------------------");
		//取出map的key集合
		Set set = map.keySet();                         //.keySet()的返回值为set类型的
		for (String string : set) {
			System.out.println(string +" ----"+map.get(string));
		}
		//取出map的value集合
		System.out.println("-------------------");
		Collection collection = map.values();          //.values()的返回值为Collection类型的
		for (Integer intrger : collection) {
			System.out.println(intrger);
		}
		//1: 获取map的entrySet集合
		System.out.println("++++++++++++++++++++++");
		Set> entryset = map.entrySet();
		for (Entry entry : entryset) {
			System.out.println(entry);
		}
		System.out.println(map.containsKey("heihei"));//判断key是否存在
		System.out.println(map.containsValue(3333));//判断value是否存在
		System.out.println(map.size());//查看Map的长度
		map.clear();
		System.out.println(map.isEmpty());//判断map是否为空
		System.out.println(map.size());

File文件/文件夹操作

	public static void method() throws IOException{
		File file = new File("E:\\ccc\\444.txt");
		if (!file.getParentFile().exists() || !file.exists()) {
			file.getParentFile().mkdirs();
			file.createNewFile();
		}
		System.out.println("------------");
		System.out.println(file.exists());
		//file.createNewFile();//创建文件
		System.out.println(file.isFile());//判断是否为文件,是文件返回true,是文件夹是false
		System.out.println(file.isDirectory());//判断是否是文件夹
		System.out.println(file.length());//获取文件的大小
		System.out.println(file.getName());//获取文件的名字
		System.out.println(file.getPath());//获取文件路径名
		System.out.println(file.lastModified());//获取文件的最后修改日期
		System.out.println(new SimpleDateFormat("YYYY-MM-DD HH:mm:ss").format(file.lastModified()));
		//file.getParentFile().delete();//file.delete();//删除文件
	}
	//遍历文件 和文件夹的方法,中间可以进行删除操作。采用了递归的方法
	public static void method2(String path) throws IOException{
		File file = new File(path);
		if (file.isDirectory()) {
			File[] files = file.listFiles();//如果是文件夹,获取所有的内容
			if (files!=null) {
				for (File file2 : files) {
					num++;
					if (file2.isDirectory()) {
						method2(file2.getPath());
						System.out.println("第"+num+"个文件夹为:\t"+file2.getPath());
					}else {
						System.out.println("第"+num+"个文件为:\t"+file2.getPath());
					}
				}
			}
		}
		
	}

最基本的输入输出流

OutputStream与InputStream

InputStream的初始化以及其方法.read()的使用方法

read方法会返回一个值:-1表示读完了,整数n表示读取了n个byte的字节数据,read读取的内容会放到指定的byte数组内,数组的大小也决定了每次调用read读取的byte字节数。

		File file = new File(path);
		InputStream inputStream = new FileInputStream(file);
		//.read 方法会返回int值,这个返回值代表是否还有数据存在,如果存在返回的是整数即读取了几个字节,不存在返回的是-1
		byte b[] = new byte[12];
		StringBuffer sb = new StringBuffer();
		int i=0;
		//每次read时读取b.length的长度的字节放到b中,下次read从上一次读取的末尾开始读取,直到读完
		//最后可能不到b.length的长度,因此拼接时只拼i个字节
		while ((i=inputStream.read(b))!=-1) {
			sb.append(new String(b,0,i));
			System.out.println(i);
		}
		inputStream.close();
		System.out.println(sb);

OutputStream

使用FileOutputStream(file);时若没有文件夹则不会创建文件夹以及文件,若是有文件夹但是没有文件则会创建文件

		File file =new File("E:\\aaa\\444.txt");
		if (file.exists()) {
			file.createNewFile();
		}
		//打开一个输出流,若不存在文件则创建文件,没有文件夹时不可以创建文件夹和文件。
		OutputStream outputStream = new FileOutputStream(file);
		String n = "同一天一到放假\n鸡飞狗叫\r\n风调雨节\n";
		//将文本转换成字节数组,然后通过输出写入到缓存中
		outputStream.write(n.getBytes());
		//将缓存中的内容写入到文件之内
		outputStream.flush();
		outputStream.close();		

reader和writer

属于基本输入输出类包装后的输入输出类,他们的区别是使用read方法读取内容时存入的数组不同,其中:

OutputStream与InputStream 存入的数组类型为 byte[]

reader和writer 存入的数组类型为 char[]

		Writer w = new FileWriter("E:"+File.separator+"444.txt");
		w.write("\n这个内容是字符输出流写到文件之中的,以后上课不积极回答问题,很有可能超代码!");
		w.flush();
		w.close();	
		Reader r = new FileReader("E:"+File.separator+"444.txt");
		char c [] = new char[12];
		int item=0;
		StringBuffer sb = new StringBuffer();
		while((item=r.read(c))!=-1){
			sb.append(new String(c, 0, item));
		}
		System.out.println(sb.toString());
		r.close();

object对象序列化存储

ObjectOutputStream与ObjectInputStream类

被存储的对象的类需要实现接口Serializable(用处不大,就是作为一个标记,不实现此接口jvm虚拟机会报错)

transient关键字

当不想存储某一种数据时可以:private transient int number;//transient关键字,对象序列化相关,存储时不会序列化number的值

Serializable接口

implements Serializable,需要使用ObjectOutputStream输入输出流的对象的类需要实现Serializable接口

package com.ishangu;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class MyDuiXiang {
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
		/*Dog d = new Dog(5,"小白","黑色",2000,"公");
		Dog d1 = new Dog(7,"小黑","黑色",3000,"母");
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("E:\\dog.hhh")));
		out.writeObject(d);
		out.writeObject(d1);
		out.close();*/
		
		//File file = new File("E:\\dog.hhh");
		//InputStream kk = new FileInputStream(file);
		//ObjectInputStream in = new ObjectInputStream(kk);
		ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("E:\\dog.hhh")));
		Dog dog = (Dog) in.readObject();
		System.out.println(dog);
		dog = (Dog) in.readObject();
		System.out.println(dog);
		in.close();
	}
}


class Dog implements Serializable{
	private int id;
	private String name ;
	private String color;
	private transient int number;//transient关键字,对象序列化相关,存储时不会序列化number的值
	private String sex;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public int getUnmber() {
		return number;
	}
	public void setUnmber(int unmber) {
		this.number = unmber;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public Dog() {
		// TODO Auto-generated constructor stub
	}
	public Dog(int id, String name, String color, int unmber, String sex) {
		super();
		this.id = id;
		this.name = name;
		this.color = color;
		this.number = unmber;
		this.sex = sex;
	}
	@Override
	public String toString() {
		return "Dog [id=" + id + ", name=" + name + ", color=" + color + ", number=" + number + ", sex=" + sex + "]";
	}
	
}

day19

多线程和线程安全

首先要了解多线程,Java中实现多线程的方法有四种

1.继承Thread类
2.实现Runnable接口
3.实现Callable接口
4.通过线程池实现多线程
Thread类: 类中封装了很多与线程有关的操作,包括线程的启动,线程的命名,线程的优先级等。
若一个类MyThread继承了Thread类,那就重写一下run()方法,便可以开启多线程。
Java多线程的代码,必须写在run方法之中,run方法不需要我们自己调用,在启动多线程的时候JVM会自动调用run
Runable接口使用前需要用一个类来实现此接口,此为常用模式,比起需要继承的Thread来说,避免了单继承
也需要把多线程的代码写在run方法之中,run方法不需要我们自己调用,在启动多线程的时候JVM会自动调用run
Callable接口和Runable接口不同,定义类实现Callable接口时需要在接口后面<>里面定义上数据的类型,并且代码
的放入位置在call方法之内。

关键字

synchronized同步关键字
synchronized(同步代码块):将需要同步的代码,尽量减少,让其他的代码能被多线程执行,这样的话既保证了多线程的效率又保证了数据的安全性。
	@Override
	public void run() {
		long l = System.currentTimeMillis();
		while(ticket>0){
			try {
				// 模拟网络卡顿,出现的情况
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized(this){
				if (ticket>0) {
					// 通过Thread类获得当前线程的名称
					System.out.println(Thread.currentThread().getName()+"开始卖票了还有 "+ticket--+" 张票");
				}			
			}		
		}
		System.out.println(Thread.currentThread().getName());
		System.out.println(System.currentTimeMillis()-l);
	}
	//这样卖票可以实现同一时间内多线程不冲突,并且多线程并行执行
	
synchronized(同步方法): Java中的悲观锁,修饰在方法之上的时候,这个方法只允许一个线程进入并且执行,只有当执行的线程离开后才允许其他在外面排队的线程进入。
@Override
	public synchronized void run() {
		System.out.println(Thread.currentThread().getName());
		while(ticket>0){
			try {
				// 模拟网络卡顿,出现的情况
				Thread.sleep(500);
			//	wait(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}							
			// 通过Thread类获得当前线程的名称
			System.out.println(Thread.currentThread().getName()+"开始卖票了还有 "+ticket--+" 张票");					
		}
	}
	//同一段时间内只能实现单线程运行

创建线程的方法

MyThread myThread = new MyThread();                //MyThread继承了Thread类,Thread类实现了Runable接口
// 通过Thread的构造方法给线程命名
Thread threadA = new Thread(myThread,"售票员A ");	//线程A执行myThread	
Thread threadB = new Thread(myThread,"售票员B ");	//线程B执行myThread
threadB.setPriority(10);	//设置线程的优先级
threadA.setPriority(1);
threadB.start();            //设置开启线程
threadA.start();
System.out.println(threadA.getName());//获得线程ThreadA的名字:售票员A
System.out.println(Thread.currentThread().getName());//获得main线程的名字

MyRunnable my = new MyRunnable();                  //MyRunnable类实现了Runable接口
new Thread(my,"售票员A ").start();
new Thread(my,"售票员B ").start();
new Thread(my,"售票员C ").start();

MyCallable my = new MyCallable();                  // 由于Callable与Thread类没有任何直接的关系,所以Thread无法直接执行Callable的实例对象,需要进行一次包装。
FutureTask<String> m1 = new FutureTask<>(my);
FutureTask<String> m2 = new FutureTask<>(my);
FutureTask<String> m3 = new FutureTask<>(my);
new Thread(m1,"售票员A ").start();
new Thread(m2,"售票员B ").start();
new Thread(m3,"售票员C ").start();
System.out.println(m1.get());
System.out.println(m2.get());
System.out.println(m3.get());

线程睡眠和唤醒

sleep: 方法源自Thread类,作用是用于线程休眠,参数为毫秒值,当线程执行到这个方法的时候会进行休眠操作,时间到了之后
会自动唤醒。
wait与sleep的区别:
1: wait属于Object类,sleep属于Thread类。
2: wait方法会释放掉锁,sleep不会释放锁。
3: wait方法可以不指定时间,等待notify或notifyAll唤醒,而sleep必须指定睡眠时间。

notify与notifyAll的区别:
notify是谁先睡眠先唤醒谁(按顺序唤醒),notifyAll是直接唤醒所有睡眠的线程。

线程安全性问题:
在卖票的时候使用sleep模拟网络延迟,结果出现了重复卖票以及票卖超的问题,在多线程的情况下如果碰到网络阻塞等情况可能会造成
数据错乱等情况。

线程的声明周期:
	1: 新建(此时线程还没有启动,指的是刚new出来线程对象。)	
	2: 就绪(此时线程已启动,指的是我们刚调用start方法,此时线程进入到就绪队列等待CPU分配资源)
	3: 运行(线程抢到CPU的资源开始执行run方法(任务),此时除非线程自动放弃CPU资源否则会一直执行到任务结束。)
	4: 阻塞(表示线程已经抢到了CPU的资源,但是因为意外情况暂停了,例如sleep,wait等此时线程可能会让出资源进入到休眠状态)
	5: 死亡(当线程任务执行完成,或者被杀死之后都会进入到死亡状态,死亡状态的线程无法进入到就绪状态)

死锁:一般是由严重的逻辑引出的,一般我们都能通过代码来避免。
何壮有个本,郭晓蝶有根笔。
何壮说你给我笔,我给你本。
郭晓蝶说你给我本,我给你笔。
死锁就是指线程A在等待线程B,而线程B也在等待线程A,双方一直等待谁都不先松手。

类的划分:

公共类:被public修饰的类,要求类名称与文件名完全一致。
普通类:没有被public修饰的类,对类名称没有要求,只要同包之下不冲突即可。

内部类:	写在别的类中的类(嵌套类),外部类无法直接访问内部类的一切,因为初始化外部类对象的时候JVM不会自动加载内部类。
	静态内部类
		1: 静态内部类可以拥有实例成员以及静态成员。
		2:静态内部类无法只能使用外部类的静态成员。
	普通内部类
		1:普通内部类只能拥有实例成员。
		2:普通内部类可以直接使用外部类的一切。
	匿名内部类
		1:没名字的类,一般在new 接口 或抽象类的时候出现,用于给抽象方法提供默认实现。
		
局部类:
	1:局部内部类一般是指声明在方法体之内的类。
	2: 可以访问并更改全局变量,但是需要收到方法体的影响(static)。
	3: 可以访问,但是无法改变方法体之内的局部变量的值。

实际上在正常开发中,内部类这种东西可有可无,一般情况下我们基本可以无视,但是如果去阅读一些源码或者以
后进行一些深层次的大型开发一个类会变得很复杂,此时可能需要内部类对一些代码进行分割管理。

day20

反射

万物皆对象

主要作用:

可以根据对象获取类的信息。Emp e = new Emp(); Class class1 = e.getClass(); class1 与Emp.class等价

可以根据类名创建类的对象。E e = class1.newInstance();

可以根据类名获取类名的属性等。Field field = class1.getDeclaredField(“empno”);

可以给新创建的类对象的属性赋值。 field.set(e, 423467);

可以把新创建的类对象e返回给调用者或者存放到list等之中,

属性
Dog d = new Dog(123);//当Dog中的属性无法获得或者改变时,可以创建一个对象,通过反射来修改新建对象的属性
Class class1 = Class.forName("com.ishangu.Dog");//通过全线命名来获得class对象
Field field1 = class1.getField("color");//获得单个属性
System.out.println("属性名称为:"+field1.getName()+"属性类型为:"+field1.getType());
Field[] fields1 = class1.getFields();   //获得全部有权限的属性
System.out.println("有权限使用的属性:");
for(Field field:fields1){
	System.out.println("属性名称为:"+field.getName()+"属性类型为:"+field.getType());
}
Field[] declaredFields = class1.getDeclaredFields();//获得全部属性
System.out.println("     所有的属性:")
for(Field field : declaredFields){
	System.out.println("属性名称为:"+field.getName()+"属性类型为:"+filed.getType());
}
Field name = class1.getDeclaredField("name");
Field color = class1.getDeclaredField("color");
Field id  = class1.getDeclaredField("id");
id.setAccessible(true);//破坏属性的访问修饰符,破坏后可以修改其值
id.set(d,123);
name.setAccessible(true);
name.set("小花");
color.set(d,"黄色"); //public修饰符的不需要破坏亦可以该值
System.out.println(d);
方法
		Dog d=new Dog(123);
		Class class1 = Class.forName("com.ishangu.Dog");
		//获取有权限使用的方法,包括父类的方法
		System.out.println("本类和父类中所有的方法:");
		Method methods[] = class1.getMethods();
		for (Method method : methods) {
			System.out.println("方法名称:"+method.getName());
		}
		//获得类中声明的所有方法
		Method[] method2 = class1.getDeclaredMethods();
		System.out.println("本类中所有的方法:");
		for (Method method : method2) {
			System.out.println(method.getName()+"参数个数是:"+
		method.getParameterCount()+"  参数的返回值类型:"+
					method.getReturnType());
			//获得方法的形参列表
			Parameter[] parameters = method.getParameters();
			for (Parameter parameter : parameters) {
				System.out.println(parameter.getName()+"类型是"+parameter.getType().getName());
			}
		}
		System.out.println("单独根据");
		Method m = class1.getDeclaredMethod("method2", String.class,Integer.class);
		m.setAccessible(true);
		//通过方法对象。invoke 闯入调用方法的对象,以及参数即可调用方法。
		System.out.println(m.getName());
		Parameter[] parameters = m.getParameters();
		for (Parameter parameter : parameters) {
			System.out.println(parameter.getName()+"_"+parameter.getType().getName());
		}
		
		m.invoke(d, "哈士奇",2);
构造方法
Class class1 = Class.forName("com.ishangu.Dog");
		//公有的构造器
		Constructor[] constructors = class1.getConstructors();
		for (Constructor constructor : constructors) {
			System.out.println(constructor.getName()+"参数有"+constructor.getParameterCount());
			Parameter[] parameters = constructor.getParameters();
			for (Parameter parameter : parameters) {
				System.out.println("构造器参数的类型是:"+parameter.getType());
			}
		}
		System.out.println("--------------------------------");
		//私有的构造器
		Constructor[] constructors2 = class1.getDeclaredConstructors();
		for (Constructor constructor : constructors2) {
			System.out.println(constructor.getName()+"参数有"+constructor.getParameterCount());
			Parameter[] parameters = constructor.getParameters();
			for (Parameter parameter : parameters) {
				System.out.println("构造器参数的类型是:"+parameter.getType());
			}
		}
		System.out.println("-----------++++++++++++------------");
		Constructor c = class1.getDeclaredConstructor();
		c.setAccessible(true);
		Dog d = (Dog) c.newInstance();
		System.out.println(d);
		Constructor c2=class1.getDeclaredConstructor(int.class);
		Dog d2 = (Dog)c2.newInstance(123);
		System.out.println(d2);
		Field id = class1.getDeclaredField("id");
		id.setAccessible(true);
		id.set(d2, 123);
		Field name = class1.getDeclaredField("name");
		name.setAccessible(true);
		name.set(d2, "余额");
		Field color = class1.getDeclaredField("color");
		color.setAccessible(true);
		color.set(d2, "白色");
		System.out.println(d2);

day21

周六

day22

设计模式

所谓的设计模式,是指被大多数人知晓,分类,并且反复使用的代码总结。
Java中的设计模式主要有23种。
为什么要用设计模式: 主要目的是为了提升代码的可重用性以及可靠性,并且让代码更好被人理解,设计模式可以让我们的
代码更加规范以及工程化。
在设计设计模式的时候(创建新的设计模式时候)需要遵守一定原则:
总原则: 开闭原则,对扩展开放,对修改关闭(是指如果需要新增功能,可以去扩展一些类,而不要修改原有代码)。
1: 单一原则
2: 里式替换原则
3: 依赖倒转原则
4: 接口隔离原则
5: 迪米特法则(最少知道原则)
6: 合成复用原则

单例设计模式:
在程序中,我们经常到处new对象,每new一个对象都会在堆内存开辟一块空间,那如果对象非常多的情况下,我们的内存
可能会溢出。
所谓的单例设计模式就是指,在程序运行过程中无论获取多少次类的实例,获得的永远都是同一个对象,不会造成对象过
多的情况,减少系统开销,减轻GC的压力。

懒汉式

懒汉式懒汉式:在最开始不对声明的队形进行初始化,而是等到调用创建对象方法的时候才进行初始化
//在当前类中声明一分自身的实例对象
	private static Singleton s ;
	
	//私有构造方法
	private Singleton (){
		
	}
public static  Singleton creatrSigleton(){
		if (s==null) {
			method();
		}
		return s;
	}
	
	private synchronized static void method(){
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		s = new Singleton();
	}
饿汉式:无论是否使用,都会占用内存空间。
//使用静态内部类,来进行加载优化,让其调用其它方法的时候不会触发对象的创建。
	private int i = 8;
	private static class A{
		//在当前类中声明一分自身的实例对象
		private static Singleton2 s = new Singleton2();
	}
	
	
	//私有构造方法
	private Singleton2 (){
		System.out.println("对象初始化了");
	}
	
	public static  Singleton2 creatrSigleton(){
		return A.s;
	}
	
	public static void method(){
		System.out.println("普通静态方法");
	}

你可能感兴趣的:(java,后端)