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: 数据数据类型之间的转换,明白什么是自动转换,什么是强制转换
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也会执行 ||与|同理
Integer.parseInt();string型字符串转换为int
尽量不要使用while(true){}
Switch()可以使用嵌套
Switch()case里面如果没有break程序会继续向下面进行直至遇见break或者结束。
需要用到if()时简单的都可以用三目运算符替代A条件D?C:B;
Math.random()* n 生成0到n的数字(为小数)
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) 对比数组中的值是否相等。
昨日内容回顾:
1: while循环以及do while的区别,以及使用
2: 数组的动态实例化以及静态实例化,数组的使用
3: Arrays工具类的使用
4:冒泡排序以及选择排序
今天内容:
今天早上我去吃饭,我遇到一个人请问我遇到的是谁?如果这样去问,大家肯定不知道我遇到了谁,
因为人这个概念太模糊了,如果我说今天早上我去吃饭我遇到了关思思,大家知道我遇到谁了么?
此时人这个概念被具体化成了关思思,这样大家都知道我遇到的是谁了。
人:
属性:性别,年龄,身高,体重
行为:吃饭,睡觉,说话
如果只是说人的话,那么人虽然有所有的属性以及行为,但是这些属性基本上都没有具体的值。
关思思:
属性:女,18,158,80
行为:吃饭,睡觉,说话
但是如果我们根据人的这个模板生成了一个具体的对象,就可以给这个对象赋值了。
猫:年龄,颜色,品种,名字
tom:81, 蓝色,短毛猫,汤姆
类:是一个非常抽象的概念,我们没有办法指着类去说它具体是指谁,因为类指向的是一个大体,类
里面抽离了所有实例对象的共有特征形成了属性,而在类中这些属性是没有具体值的,因为这些属性
虽然写在类中,但是属性具体的值却属于通过类实例化出来的对象。
对象:通过类创建出来的实例(对象就是类的实例化体现),类是比较抽象的概念,而对象却是一个具体的
概念,每个对象都有自己的属性,与其他对象无关。
我们可以简单理解成:
类是一个设计图纸,这个设计图纸上虽然标注的有形状,样子,等很多属性,但是在图纸上并不是真实存在
的,如果我们通过设计图作出了真正的产品,那么产品的值就是真实存在在的。
一:类主要是由属性(变量),方法,代码块组成。
变量的划分:
1:直接声明在类中,其作用域是整个类。
2:全局变量是由默认初始值的(不需要初始化也可以直接使用)。
全局变量有两种
1:被static修饰的变量,存储在常量池之中,被所有对象共享,并且可以直接通过类名调用。
2:没有static修饰的变量,存储在堆内存中,每个对象都有自己的一份,不会共享,只能通过
对象名.调用。
1: 一般声明在方法之内,作用域一般都是声明时候的作用域,例如如果直接声明在方法中,作用域
就是整个方法,如果声明在方法体中的for循环作用域里,变量的作用域就只是这个for循环。
2: 局部变量没有默认初始值,这就是说局部变量必须初始化之后才能使用。
什么时候使用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 ab;
(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
面向对象的三大特征:
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.方法() 表示调用父类的方法
1: 重写是发生在父子类关系之中的,方法名称需要与父类方法名一致。
2: 形参列表需要与父类一致。
3: 返回值类型需要与父类一致。
4:要求子类的访问修饰符不能比父类更严格。
当我们将对象放入到输出语句的时候,默认会自动调用toString方法,那么我们只要重写toString方法,让toString方法返回对象信息的字符串,就可以实现输出对象的时候直接输出对象
的所有信息。
1:修饰在变量上,让其变成常量。
2:修饰在类上,final修饰的类不能被继承,String就是被final修饰的所以不能被继承。
3:修饰在方法上,final修饰的方法不能被子类重写。
1: static修饰在变量上,变量会变成静态成员,可以被类直接调用。
2: static修饰在方法上,方法会变成静态方法,可以被类直接调用。
3: static修饰在类上,叫做静态类
4: static修饰在代码块,叫做静态块。
1:静态块 直接写在类中,被static修饰的代码块,只有在类第一次被加载的时候会执行一次。
2:构造块 直接写在类中,无任何修饰的代码块,每次创建对象的时候都会执行一次。
3:普通块 写在方法之中,可以避免方法中的变量名冲突,但是同时也局限了变量的作用域。
4:同步块------预留后期多线程时候将
静态块–优先所有–>构造块—优先自身—>构造方法
见day11
接口中的常量默认被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.在以后的项目中,我们可能会使用很多常量值,如果常量值的定义到处都是的时候很麻烦,此时可以将所有的常量都保存在接口中
*/
就是指多个形态。
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:
String类, StringBuffer , StringBuilder ,Object类,[System类],Math类,Date类,Calendar类,DateFormat类,Byte类,Short类,Integer类,Long类,Float类,Double类,Boolean类,Character类,BigInteger类,BigDecimal类,Arrays类。
String.format String.split(String regex)
String regionMatches()测试两个字符串区域是否相等
String indexof() 返回指定字符第一次出现的字符串内的索引。
String.join
Byte.toUnsignedInt
Character:digit, //无用
Dateformat类是时间格式化类,专门用于格式化时间使用
calendar类是日历类,可以单独设置或取出年月日等操作
sc.subSequence(2, 4)返回的是下标2,3的子序列?
BigDecimal : plus() 舍入
Long reverse
String matches 正则表达式
1:toLowerCase(Locale locale)
将所有在此字符 String ,以降低使用给定的规则情况下 Locale
4:clone()。 //有可能会将,也有可能不会将。
5:System.getproperty与setproperty有什么用,主要用于获取以及设置一些系统属性。
6:append(CharSequence s) 追加指定的 CharSequence到这个序列。
7:DateForma : parse(String source) 。 从给定字符串的开始解析文本以生成日期
8:notify();唤醒正在等待对象监视器的单个线程。
9:notifyAll(); 唤醒正在等待对象监视器的所有线程
10:offsetByCodePoints(char[] a, int start, int count, int index, int codePointOffset)
返回给定的 char子阵列中的索引,该子阵列与 index由 codePointOffset代码点偏移。
Arrays:
parallelPrefix(double[] array, DoubleBinaryOperator op)
setAll(int[] array, IntUnaryOperator generator)
spliterator(int[] array)
stream(int[] array)
StringBuffer:
int offsetByCodePoints(int index, int codePointOffset)
int 跟 integer 或char与Character 这种基本数据类型和复杂数据类型有何区别,
为什么要有复杂数据类型,复杂数据类型的作用以及用在何处。
*************************************异常体系*****************************************
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:预习集合
为什么要有异常:
异常实际上是一个类似警告牌一样的功能,在方法中合理创建异常对象可以提醒方法调用者需要
注意的内容,以及在方法调用者出现问题的时候可以给与解决提示。
异常的处理流程:
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;
}
}
YDemo12
MyArraysList和MyLinkedLink的解说
集合图里面的内容,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继承于AbstractList继承于AbstractCollection实现了接口Collection
集合类,继承于AbstractList,并且实现了List接口。
1:底层由数组实现,有序并且值可以重复。
2:默认初始容量是10,每次扩容都是1.5倍,可以通过构造方法指定初始容量。
3:由于存在下标,所以查询和修改速度较快,但是删除和插入较慢。
4:线程不安全,效率较快。
Vector继承于AbstractList继承于AbstractCollection实现了接口Collection
集合类,继承于AbstractList,并且实现了List接口。
1:底层由数组实现,有序并且值可以重复。
2:默认初始容量是10,每次扩容都是2倍,可以通过构造方法指定初始容量。
3:由于存在下标,所以查询和修改速度较快,但是删除和插入较慢。
4:线程安全,效率较慢。
AbstractSequentialList: 继承于AbstractList,定义了一些为链表提供的顺序操作。
Stack: Vector的子类,诞生于JDK1.0,基本没有使用了。
Deque: 是一个双端队列接口,继承于Queue接口。
ArrayDeque: Deque的实现类,是一个双端队列的集合,同时继承了AbstractCollection。
LinkedList继承于AbstractSequentialList继承于AbstractList继承于AbstractCollection实现了接口Collection
集合类,实现了Deque队列接口以及List接口的同时又继承了AbstractSequentialList。
1:底层是由双线链表+双端队列实现。
2:由于链表的底层不存在原生下标,所以查询与修改较慢(没有下标,需要不断遍历),插入和删除较快(没有下标,不需要维护)。
AbstractSet 对set接口的内容提供了基本的实现,同时继承了AbstractCollection以及实现了set接口。
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继承于AbstractSet继承于AbstraceCollection实现了接口Collection,HashSet实现了Set接口
集合类,实现了Set接口,同时继承了AbstractSet。
1: HashSet集合是无序的,并且值不能重复。
2:HashSet在代码中创建了一个HashMap对象,将值存入到Map的Key上面,所有的操作都是通过HashMap来完成。
SortedSet: 接口 里面定义了一些比较方面相关的内容,想为set提供排序的方法。
NavigableSet接口 完善了SortedSet比较和排序的方法规范,继承了SortedSet。
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使用的是HashMap里面的方法 底层为哈希表
HashSet与TreeSet里面存储的内容不可以重复
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如何进行排序。
map的实现方法讲解(put,get),map主要使用的是table数组(transient Node
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());
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();
属于基本输入输出类包装后的输入输出类,他们的区别是使用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();
ObjectOutputStream与ObjectInputStream类
被存储的对象的类需要实现接口Serializable(用处不大,就是作为一个标记,不实现此接口jvm虚拟机会报错)
当不想存储某一种数据时可以:private transient int number;//transient关键字,对象序列化相关,存储时不会序列化number的值
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 + "]";
}
}
首先要了解多线程,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: 可以访问,但是无法改变方法体之内的局部变量的值。
实际上在正常开发中,内部类这种东西可有可无,一般情况下我们基本可以无视,但是如果去阅读一些源码或者以
后进行一些深层次的大型开发一个类会变得很复杂,此时可能需要内部类对一些代码进行分割管理。
万物皆对象
主要作用:
可以根据对象获取类的信息。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);
周六
所谓的设计模式,是指被大多数人知晓,分类,并且反复使用的代码总结。
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("普通静态方法");
}