一、对象:真实存在的唯一的事物。
二、类:同一种类型的事物公共属性与公共行为的抽取。
三、Java面向对象语言:
1、核心思想:找适合的对象做适合的事情。
2、找对象的方式:
方式一:sun已经定义好了很多类,我们只需要认识这些类即可创建对象使用。
方式二:我们需要自定义类,通过自定义类创建对象。
四、自定义类三步骤:
1、 自定义一个类。
class 类{
事物的公共属性使用成员变量描述。
事物的公共行为使用函数描述。
}
2、 可以通过类创建对象。
3、 访问(设置)对象的属性或者调用对象的方法。
五、成员变量与局部变量的区别:
1、 自定义的位置区别:
(1) 成员变量是定义在方法之外,类之内的变量。
(2) 局部变量是声明在方法之内的变量。
2、 作用上的区别:
(1) 成员变量的作用是描述一类事物的属性。
(2) 局部变量的作用是提供一个变量给方法内部使用的。
3、 生命周期的区别:
(1) 成员变量随着对象的创建而存在,随着对象的消失而消失。
(2) 局部变量时调用到了对应的方法执行到了创建该变量的语句时存在,一旦出了自己的作用域马上从内存消失。
4、 初始值的区别:
(1) 成员变量是有默认的初始值的。
(2) 局部变量是没有默认的初始值的,必须要先初始化才能使用。
六、匿名对象:没有引用类型变量指向的对象就称作为匿名对象。
七、匿名对象要注意的细节:
1、 一般不会给匿名对象的属性赋值,因为永远都无法获取到。
2、 两个匿名对象永远都不可能是同一个对象。
八、匿名对象好处:简化书写。
九、匿名对象的应用场景:
1、 如果调用一个对象的方法一次时,然后这个对象就不再使用,那么这时候可以匿名对象。
2、 可以作为实参调用一个函数。
十、封装:将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。
十一、封装的步骤:
1、 使用private修饰需要被封装的属性。
2、 根据需要提供get或者set方法设置以及获取属性。
十二、封装的好处:
1、 提高了数据的安全性。
2、 操作简单。
3、 隐藏了实现。
注意:一般实体类的属性我们都会封装起来。
构造函数:
构造函数的作用:初始化对应的对象。
构造函数的格式:
修饰符 函数名(形式参数){
函数体
}
构造函数要注意的事项:
(1) 构造函数是没有返回值类型的。
(2) 构造函数的函数名是必须与类名一致。
(3) 构造函数不是由我们手动调用的,是我们在创建了对应的对象时,jvm会根据你创建的对象传递的参数调用对应的对象。
(4) 如果一个类没有显示写上一个构造函数的时候,那么java编译器会为该类添加一个无参的构造函数。
(5) 如果一个类已经显示写上一个构造函数的时候,那么java编译器则不会再为该类添加一个无参的构造函数。
(6) 构造函数是可以以函数重载的形式存在多个。
构造代码块:
构造代码块的作用:给对象进行统一的初始化。
构造代码块的格式:
{
代码;
}
构造代码块是在创建了代码块所属类的对象时调用一次。
this关键字:
this关键字代表了所属函数的调用者对象。
this关键字的作用:
(1) 一个类中存在同名的成员变量与局部变量时,在方法的内部默认是访问局部变量的,可以通过this关键字指定访问成员变量得数据。
(2) this关键字还可以在构造函数中调用另外一个构造函数初始化对象。
this关键字调用构造函数要注意的事项:
(1) this关键字调用其他的构造函数时,必须要是在第一个语句。
(2) this关键字调用构造函数时不能出现相互调用,因为是一个死循环。
(3) 如果在方法的内部访问一个变量时,该变量只存在于成员变量中,局部变量没有,这时候java编译器会为该变量前面添加一个this关键字。
static (静态、修饰符)
static修饰成员变量时:static修饰成员变量时,那么该成员变量的数据就是一个共享的数据。
静态成员变量的访问方式:
方式一:使用对象进行访问。
对象.属性名
方式二:可以使用类名进行访问
类名.属性名
注意:
(1) 非静态成员变量不能类名直接访问,只能使用对象进行访问。
(2) 千万不要为了方便访问成员变量而使用static修饰,一定要是该数据是共享数据时才使用static修饰。
static修饰方法(静态的成员方法):
访问方式:
方式一:可以使用对象进行访问。
对象.静态的函数名();
方式二:可以使用类名进行访问。
类名.静态函数名字()。
推荐使用是类名直接访问静态方法
静态函数要注意的事项:
(1) 静态函数是可以调用类名或者对象进行调用的,而非静态函数只能使用对象进行调用。
(2) 静态的函数可以直接访问静态的成员,但是不能直接访问非静态的成员。
原因:静态函数是可以使用类名直接调用的,这时候可能还没有存在对象,而非静态的成员数据是随着对象的存在而存在的。
(3) 非静态的函数是可以直接访问静态与非静态的成员。
原因:非静态函数只能由对象调用,当对象存在的时候,静态数据老早就已经存在了,而非静态数据也随着对象的创建而存在了。
(4) 静态函数不能出现this或者super关键字。
原因:因为静态的函数是可以使用类名调用的,一旦使用类名调用这时候不存在对象,而this关键字代表了一个函数的调用者对象,这时候产生了冲突
静态代码块:静态代码块是类名.class文件加载到内存的时候就马上执行的.
静态的数据的生命周期:
静态的成员变量数据是优先于对象存在的。
/*静态方法与非静态方法的字节码文件是同时存在内存中的,只是静态的成员变量数据是优先于对象存在而已*/
单例设计模式:保证一个类在内存中只有一个对象。
饿汉单例设计模式:
1、 私有化构造函数。
2、 声明本类的引用类型变量并且指向本类的对象,(private static)
3、 提供一个公共静态的方法获取本类对象。
懒汉单例设计模式:
1、 私有化构造函数。
2、 声明本类的引用类型变量,但是不要创建对象。
3、 提供一个公共静态的方法获取本类对象,获取之前先判断是否已经创建了本类的对象,如果没有创建,创建再访问。如果已经创建了,那么直接访问即可。
继承:
继承的格式:
class类名1 extends 类名2{
}
继承要注意的事项:
1、 父类私有的成员不能被继承。
2、 父类的构造函数不能被继承。
3、 创建子类对象时,默认会先调用父类的无参构造函数,然后再调用子类的构造函数。
super 关键字:super关键字代表的是父类的引用空间。
super关键字的作用:
1、 如果子父类存在同名的成员时,在子类中默认是访问子类的成员,可以通过super关键字指定访问父类的成员。
2、 创建子类对象时,默认会先调用父类的无参构造函数,可以通过super关键字指定调用父类的构造函数。
super 关键字要注意的事项:
1、 如果在子类的构造函数中没有指定调用具体父类构造函数,那么java编译器会在子类的构造函数上添加super();
2、 super 关键字调用构造函数时必须出现构造函数中第一个语句。
3、 this 与super调用构造函数的时候不能同时出现在一个构造函数中,因为都需要是第一个语句。
方法重写:子父类存在着同名的函数。
方法重写的需求:如果父类的功能无法满足子类的需求,那么就进行重写。
方法重写的要求:
1、 函数名与形参列表必须一致。
2、 子类的权限修饰符必须大于或者等于父类的权限修饰符。
3、 子类的返回值类型必须小于或者等于父类的返回值类型。
4、 子类抛出的异常类型必须要小于或者等于父类抛出的异常类型。
instanceof 关键字:判断一个对象是否属于某种类型。
instanceof关键字的使用格式:
对象 instanceof类。
instanceof的使用前提:判断的对象与类型必须存在继承或者实现的关系。
抽象类:
什么时候使用抽象类:
描述一类事物的时候,发现该事物确实存在着某种行为,但是目前这种是不具体的,这时候应该抽取这种行为的声明,而不去实现该种行为,这时候这种行为我们把它称为抽象的行为,这时候应该使用抽象类。
抽象类要注意的细节:
1、 如果一个方法没有方法体,那么该方法必须使用abstract修饰
2、 如果一个类含有抽象方法,那么这个类肯定是一个抽象类或者接口。
3、 抽象类不能创建对象。
4、 抽象类是含有构造方法的。
5、 抽象类可以存在非抽象方法与抽象方法。
6、 抽象类可以不存在抽象方法。
7、 非抽象类继承抽象类的时候,必须要把抽象类中所有抽象方法全部实现。
abstract 不能与以下关键字一起使用:
1、 abstract 不能与static共同修饰一个方法。
2、 abstract不能与private公共修饰一个方法。
3、 abstract 不能以final关键字共同修饰一个方法。
接口:
接口的定义格式:
interface接口名{
成员变量
成员函数…
}
接口的作用:
1、 程序解耦。
2、 定义约束规范。
3、 拓展功能。
接口要注意的细节:
1、 接口中成员变量都是常量,默认的修饰符是 public static final
2、 接口中的方法全部都是抽象方法,默认的修饰符:public abstract
3、 接口不能创建对象。
4、 接口是没有构造函数的。
5、 非抽象类通过implements实现接口的时候,必须要把接口中所有方法全部实现。
接口与接口之间的关系:实现关系。
注意:一个类可以实现多个接口。
接口与接口之间的关系:继承关系
注意:一个接口是可以继承多个接口的。
多态:父类的引用类型变量指向了子类的对象,或者是接口的引用类型变量指向了接口实现类的对象。
多态要注意的细节:
1、 多态情况下,如果子父类存在同名的成员变量时,访问的是父类的成员变量。
2、 多态情况下,如果子父类存在同名的非静态函数时,访问的是子类的成员函数。
3、 多态情况下,如果子父类存在同名的静态函数时,访问的是父类的成员函数。
4、 多态情况下,不能访问子类特有的成员。
多态的应用:
1、 多态用于形参类型的时候,可以接收更多类型的数据。
2、 多态用于返回值类型的时候,可以放回更多类型的数据。
内部类:
内部类类别:
成员内部类:在一个类的成员位置定义另外一个类,那么另外一个类就称作为成员内部类。
成员内部类的访问方式:
方式一:在外部类内提供一个方法创建内部类的对象进行访问。
方式二:在其他类创建内部类的对象进行访问。
创建的格式:外部类.内部类 变量名 = new 外部类().new 内部类();
注意:如果是静态内部类在其他类的创建对象方式:
外部类.内部类 变量名 = new 外部类.内部类();
成员内部类要注意的事项:
1、 成员内部类可以直接访问外部类成员。
2、 如果成员内部与外部类存在同名的成员,默认是访问内部类的成员,可以通过外部类.this.成员指定放完外部类的成员。
3、 如果成员内部类出现了静态的成员,那么该成员内部类也必须使用static修饰。
4、 如果成员内部类是私有的,那么创建内部类的对象就只能在外部类提供方法创建。
局部内部类:在一个类的方法内部定义另外一个类,那么另外一个类就称作为局部内部类。
局部内部类要注意:如果局部内部类访问了局部变量,那么该变量需要使用final修饰。(原因:因为生命周期不一致,所以内部类访问局部变量其实是一个复制品)
匿名内部类:没有类名的类。
匿名内部类的好处:简化书写。
匿名内部类的使用前提:必须存在继承或者实现关系。
匿名内部类的格式:
new父类(父接口){
匿名内部类的成员;
};
异常:
异常的体系:
---------|Throwable
---------------|Error(错误)错误一般是由于jvm或者是硬件引发的问题,所以我们一般都不会通过代码去处理。
---------------|Exception(异常)异常我们一般都会通过代码去处理的,
异常的处理方式:
方式一:捕获处理
捕获处理的格式:
try{
可能发生异常的代码
}catch(捕获的异常类型变量名){
处理异常的代码
}
捕获处理要注意的细节:
1、 如果一个try块中出现了异常的代码,经过处理之后,那么try-catch块外面的代码可以正常执行。
2、 如果一个try块中出现了异常的代码,那么在try块中出现异常的代码后面的语句无法执行。
3、 一个try块后面可以跟多个catch块,也就是一个try块可以捕获多种异常的类型,但是捕获的异常类型必须从小到大进行捕获。
方式二:抛出处理(throw throws)
抛出处理要注意的细节:
1、 如果一个方法内部抛出了一个编译时异常对象,那么该方法必须要声明抛出。
2、 如果调用了一个声明抛出编译时异常的方法,那么调用者必须要处理。
3、 如果一个方法抛出了一个异常对象,那么该方法也会马上停止(一个方法遇到了throw关键字,那么该方法就会马上听孩子自)
4、 在一种情况下只能抛出一种异常对象。
throw关键字是用于方法体之内抛出异常对象的,throws是用于方法声明上声明抛出异常类型的。
进程:进程就是正在运行的应用程序。进程负责内存空间的划分。
线程:一个进程中的代码是由线程去执行的,线程也就是进程中一个执行路径。
多线程:一个进程中有多个线程可以同时执行任务。
多线程的好处:
1、 解决一个进程中可以同时执行多个任务的问题。
2、 提高了资源利用率
多线程的弊端:
1、 增加了cpu的负担。
2、 降低了一个进程中线程的执行概率。
3、 出现了线程安全问题
4、 会引发死锁现象。
自定义线程的实现方式:
方式一:
1、 自定义一个类继承Thread类
2、 重写Thread类的run方法,把自定义线程的任务代码写在run方法上。
3、 创建Thread的子类对象,并且调用start方法启动一个线程。
注意:千万不要直接调用run方法,调用start方法的时候线程就会开启,线程一旦开启就会执行run方法中代码,如果直接调用run方法,那么就相当于调用了一个普通的方法而已。
线程安全问题:
1、 存在两个或者两个以上的线程对象共享同一个资源。
2、 多线程操作共享资源的代码有多句。
线程安全问题的解决方案:
方式一:可以使用同步代码块去解决
格式:
Synchronized(锁对象){
需要被同步的代码。
}
同步代码块要注意的事项:
1、 锁对象可以是任意的一个对象。
2、 一个线程在同步代码块中sleep了,并不会释放锁对象。
3、 如果不存在着线程安全问题,千万不要使用同步代码块,因为会降低效率
4、 锁对象必须是多线程共享的一个资源,否则锁不住。
集合体系:
----------|Collection 单例集合的根接口
-------------------|List 如果是实现了List接口的集合类,具备的特点:有序,可重复
------------------------|ArrayList ArrayList 底层是维护了一个Object数组实现的。特点:查询速度快,增删慢
------------------------|LinkedList LinkedList 底层是使用了链表数据结构实现的,特点:查询速度慢,增删快。
------------------------|Vector Vector 的实现与ArrayList是一致,但是线程安全的,操作效率低,JDK1.0的时候出现的
----------|Set 如果是实现了Set接口的集合类,具备的特点:无序,不可重复。
----------------------------| HashSet 底层是使用了一个哈希表支持的,特点:存储速度快。
HashSet 添加元素的原理:
往HashSet添加元素的时候,首先HashSet会调用元素的hashCode方法得到元素的哈希码值,然后会经过一系列运算就可以算出该元素在哈希表中的存储位置
情况一:如果算出该元素的位置目前没有任何元素存储,那么该元素可以直接存储
情况二:如果算出该元素的位置目前已经存有其他的元素,那么还会调用元素的equals方法与该位置的元素再比较一次,如果equals方法返回的是false,那么该元素允许存储,如果equals方法返回的是true,那么该元素被视为重复元素,不允许存储。
-----------------------------| TreeSet 底层是使用了红黑树(二叉树)数据结构实现的,特点:会对元素进行排序存储。
TreeSet要注意的事项:
1、 往TreeSet添加元素的时候,如果元素本身具备自然顺序的特性,那么会根据元素自然顺序的特性进行排序存储。
2、 往TreeSet 添加元素的时候,如果元素本身不具备自然顺序的特性,那么元素所属的类必须要实现Comparable接口,把元素的比较规则定义在CompareTo方法上。
3、 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,而且元素所属的类没有实现Comparable接口,那么必须要在创建TreeSet对象的时候传入比较器。
4、 如果比较的方法(ComapareTo或者 Compare)返回的是0的时候,那么该元素就被视为重复元素,不允许添加。
比较器的定义格式:自定义一个类实现Comparator接口即可
class 类名 implementsComparator{
}
泛型:泛型是JDK1.5出现的新特性
泛型的好处:
1、 将运行时出现的问题提前至了编译时。
2、 避免了无谓强制类型转换。
自定义泛型:自定义泛型就是一个数据类型的占位符或者理解为一个数据类型的变量。
泛型方法:
修饰符<声明自定义的泛型>返回值类型 函数名(自定义的泛型 变量名….)
泛型方法要注意的事项:
1、 泛型方法中的自定义泛型的具体数据类型是在调用该函数的时候传入实参时确定的。
2、 自定义泛型所用的标识符只要符合标识符的命名规则即可。但是我们一般都习惯使用一个大写字母
泛型类:
泛型类的定义格式:
class类名<声明自定义的泛型>{
}
泛型类要注意的事项:
1、 泛型类上的自定义泛型是在使用该类创建对象的时候指定具体的数据类型的。
2、 如果一个类已经自定义了泛型,使用该类创建对象的时候如果没有指定泛型的具体数据类型,那么默认为Object类型。
3、 静态的函数不能使用类自定义的泛型,如果静态函数需要使用,必须要在函数上自定义泛型。
泛型接口:
泛型接口的定义格式:
interface接口名<声明自定义的泛型>{
}
泛型接口要注意的事项:
1、 泛型接口上的自定义泛型是在实现该接口的时候指定具体数据类型的。
2、 如果实现接口的时候没有指定接口上的自定义泛型的具体数据类型,那么默认是Object数据类型。
3、 如果需要在创建接口实现类对象的时候才指定接口上自定义泛型,那么需要以下格式:
class<T> 类名 implemnts 接口<T>
泛型上下限:
?super Integer 允许是Integer数据类型或者是Integer父类类型 泛型的下限
?extends Number 允许是Number数据类型或者是Number子类的数据类型 泛型的上限
Eclipse 常用快捷键
alt+ / 内容补全键
ctrl+1 快速修复键
alt + 上下方向键 移动代码
tab 整体向右移动
shift + tab 整体想左移动
ctrl + shift + / 添加多行注释
ctrl + shift + \ 取消多行注释
ctrl + / 取消或者添加单行注释
ctrl + shift + f 代码格式化
ctrl + shift + o 快速导包
ctrl + d 删除当前行代码
按住ctrl+鼠标点击 或者 是按F3 查看源代码
ctrl + shift + t 查看源代码
ctrl + shift + x 更改为大写
ctrl + shift + y 更改为小写
断点调试:可以让程序停留在指定的地方,然后去观察目前程序的数据,然后分析错误的原因
step over 跳过本行代码
stem into 进入方法内部
step return 结束方法,返回数据。
字节流:
输入字节流
----------| InputStream 输入字节流的基类 抽象类
--------------| FileInputStream 读取文件数据的输入字节流
--------------| BufferedInputStream 缓冲输入字节流 缓冲输入字节流出现的目的:为了提高读取文件数据效率。该类其实内部就是维护了一个8Kb字节的数组
输出字节流:
------------| OutputStream 输出字节流的基类 抽象类
----------------| FileOutputStream 向文件输出数据的输出字节流
----------------| BufferedOutputStream 缓冲输出字节流。该类出现的目的为了提高写数据的效率。其实该类内部也是维护了一个8kb字节的数组而已。当调用其write方法的时候数据默认是向它内部的数组中存储的,只有调用flush方法或者是close方法或者是8kb的字节数组存储满数据的时候才会真正的向硬盘输出
字符流:字符流= 字节流+ 编码(解码)
输入字符流:
-------------| Reader 所有输入字符流的基类。抽象类
------------------| FileReader 读取文件数据的输入字符流
------------------| BufferedReader 缓冲输入字符流 该类出现的目的是为了提高读取文件数据的效率与拓展FileReader的功能(readLine)功能,这个类也只不过是在内部维护了一个8kb的字符数组而已。
输出字符流:
-------------| Writer 所有输出字符流的基类。抽象类
--------------------| FileWriter 向文件输出数据的输出字符流。
--------------------| BufferedWriter 缓冲输出字符流 该类出现的目的是为了提高写文件数据的效率与拓展FileWriter的(newLine)功能。
转换流:
输入字节流的转换流: InputStreamReader
InputStream--------------------àReader
输出字节流的转换流: OutputStreamWriter
OutputStream-----------------àWriter
转换流的作用:
1、 可以把字节流转换成字符流使用。
2、 FileReader与FileWriter都是固定是GBK码表进行读写数据的,而转换流可以指定码表进行读写文件的数据
Properties(配置文件)
体系:
-----------|Map
-----------------|HashTable
---------------------------|Properties 配置文件类
store()用于生成一个配置文件
load()加载一个配置文件
注意:
1、 如果配置文件存在着中文,那么生成配置文件的时候要使用字符流,否则会出现乱码
2、 如果需要修改配置文件的内容,应该先加载原本配置文件,然后再生成一个配置文件。
continue 跳过本次循环语句,继续下一次循环。
continue的作用范围:只能适用于循环语句。
一旦执行了continue语句,那么在循环体内continue之后的循环语句跳过执行。
break 结束当前所在的循环。如果配合标识符的使用,可以作用于外层的for循环。
return
函数重载:在一个类中出现了两个或者两个以上的同名函数称作为函数的重载。
函数重载的作用:一个函数名可以应对各种不同类型的参数。
函数重载的要求:
1、 函数名一致;
2、 形参列表不一致(形参的个数不一致或者是形参对应的类型不一致)
函数重写:子父类出现了同名的函数称之为函数的重写。
函数重写必须要是在继承的关系才存在的。
函数重写的需求:父类的功能无法满足子类的需求。
函数重写的要求:
1、 子父类的函数名与形参列表必须一致
2、 子类的权限修饰符必须要大于或者等于父类的权限修饰符
3、 子类的返回值类型必须要小于或者等于父类的返回值类型。
4、 子类抛出的异常类型必须要小于或者等于父类抛出的异常类型
冒泡排序:相邻的两个元素比较,符合条件交换位置
匿名对象:没有引用类型变量指向的对象就称作为匿名对象。
匿名对象的主要作用:简化书写。
匿名对象主要用于两种应用场景:
1、 如果一个对象的方法只会调用一次的时候,然后该对象就不在使用了,这时候就可以使用匿名对象。
2、 作为参数传递
封装:
封装的步骤:
1、 私有化要封装的属性;
2、 根据需求提供对应的get或者是set方法
封装的好处:
1、 提高数据的安全性。
2、 操作简单。
3、 隐藏实现。
封装一定会用的场景:如果是实体类的成员属性,我们在现实开发中全部都封装起来。
构造代码块:给对象进行统一的初始化
应用场景:如果创建任意对象的时候都需要调用某个方法为该对象进行初始化时,这时候就可以使用构造代码块。(构造代码块的代码其实是在构造函数中执行的)
静态代码块:静态代码块是静态代码块所属的类被加载到内存的时候执行的。
静态代码块的应用场景:以后主要用于准备一个项目的初始化工作。
比如:从配置文件中读取数据库用户名和密码。
instanceof 判断指定的对象是否属于某种类别
instanceof 使用前提: 判断的对象与类别必须存在继承或者实现的关系。
instanceof 使用格式:
对象 instanceof类别。
有多态才可能使用到instanceof 关键字
主要应用场景:数据类型强转之前的判断。
抽象类的应用场景:描述一类事物的时候,如果该类确实存在某种行为,但是目前这种行为是不具体的,这时候就可以把这种行为描述成抽象的行为,这时候使用抽象类。
继承的问题:隐式继承
多态:父类的引用类型变量指向了子类的对象,或者是接口的引用类型变量指向了接口实现类的对象。
应用:
1、多态应用于形参类型的时候,可以接收更多类型的参数;
2、多态用于返回值类型的时候,可以返回更多类型的参数;
迭代器的作用:用于获取集合中的元素
内部类:
内部类的好处:内部类可以直接访问外部类的成员。
匿名对象:没有引用类型变量指向的对象就称作为匿名对象。
匿名内部类:没有类名的类就称作为匿名内部类
匿名内部类的使用前提:必须存在继承或者实现关系
因为匿名内部类没有类名,所以创建匿名内部类对象的时候就必须要借助于它父类的名字或者它父类接口的名字来创建,但是匿名内部类只不过是没有类名,其他的一概成员都是具备的。
匿名内部类的应用场景:主要是作为参数传递使用。
线程:
多线程存在的意义:解决了一个进程允许多个任务可以同时执行。
多线程的创建方式:
方式一:继承Thread
1、 自定义一个类继承Thread;
2、 重写Thread的run方法,把自定义线程的任务代码放在run方法上;
3、 创建Thread类的子类对象,并且调用start方法开启线程。
方式二:实现Runnable接口
1、 自定义一个类实现Runnable接口;
2、 实现Runnable的run方法,把自定义线程的任务代码放在run方法上;
3、 创建Runnable实现类的对象;
4、 创建Thread对象,然后把Runnable实现类的对象作为参数传递;
5、 调用Thread对象的start方法开启线程。
锁:
Java中的同步机制:
出现线程安全问题的根本原因:
1、 存在两个或者两个以上的线程共享资源;
2、 操作资源的代码块必须有语句。
1、 同步代码块:
同步代码块的格式:
Synchronized(锁对象){
需要被同步的代码块…
}
同步代码块要注意的细节:
1、 锁对象可以是任意对象;
2、 锁对象必须是多线程共享的资源,否则锁不住;
3、 没有现成安全问题的时候不要使用锁,因为会导致效率降低;
4、 调用sleep方法并不会释放锁对象,但是调用wait方法的线程就会释放锁对象。
2、 同步函数:
修饰符 synchronized 返回值类型函数名(形参列表…){
}
注意:
1、 同步函数的锁对象是不能任意的,非静态同步函数的锁对象this对象,静态函数的锁对象是当前字节码对象;
2、 同步函数的锁对象不能由你指定,是固定的。
集合:
单例集合
-------|Collection 单例集合的根接口
------------|List 如果是实现了List接口集合类具备的特点:有序,可重复
----------------|ArrayLisst 底层使用Object数组实现的,特点:查询速度快,增删慢
----------------|LinkedList 底层是使用了链表数据数据结构实现的,特点:查询慢,增删快----------------| Vector(了解)底层使用Object数组实现的,实现与ArrayList是一样的,只不过是线程安全的。操作效率低。
--------------|Set 如果是实现了Set接口集合类具备的特点:无序,不可重复
-----------------|HashSet 底层使用的是哈希表实现的
-----------------|TreeSet 底层使用二叉数实现
双例集合:
--------|Map (只需要把Map接口的方法全部练习一次即可)
------------|HashMap 底层使用的是哈希表实现的
------------|TreeMap 底层使用二叉树实现
------------|HashTable (了解)
集合:存储对象数据的集合容器。
单例集合:
-----------|Collection 单例集合的根接口
------------------|List 如果是实现了List接口的集合类,具备的特点:有序,可重复 -------------------------| ArrayList 底层是使用了Object数组实现的,特点:查询速度快,增删慢
-------------------------|LinkedList 底层是使用了链表数据结构实现的,特点:查询速度慢,增删快
-------------------------|Vector 底层是使用了Object数组实现的,实现原理与ArrayList是一致的,但是线程是安全的,操作效率低。
------------------|Set 如果是实现了Set接口的集合类,具备的特点:无序,不可重复
-------------------------|HashSet 底层是使用了哈希表实现的,特点:存取速度快。
-------------------------|TreeSet 底层是使用了二叉树(红黑树)数据结构实现的,特点:对集合中的元素进行排序存储。
HashSet存储元素的原理:
往HashSet添加元素的时候,首先会调用元素的hashCode方法得到元素的哈希码值,然后把哈希码值经过运算算出该元素存在哈希表中的位置;
情况1:如果算出的位置目前还没有存在任何元素,那么该元素可以直接添加到哈希表中。
情况2:如果算出的位置目前已经存在其他的元素,那么还会调用元素的equals方法再与这个位置上的元素比较一次。如果equals方法返回的是true,那么该元素被视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素也可以被添加。
TreeSet要注意的事项:
1、 往TreeSet添加元素的时候,首先如果元素具备自然顺序的特性,那么TreeSet会根据元素的自然顺序特性进行排序存储。
2、 往TreeSet添加元素的时候,如果元素不具备自然顺序的特性,那么元素所属的类就必须要实现Comparable接口,把比较的规则定义在ComparableTo方法上。
3、 往TreeSet添加元素的时候,如果元素不具备自然顺序的特性,那么元素所属的类也没有实现Comparable接口,那么在创建TreeSet对象的时候必须要传入比较器对象。
比较器的定义格式:
class 类名 implementsComparator{
}
双例集合
-----------|Map 存储的元素都是以键值对的形式存在的,键不可以重复,值可以重复
------------------|HashMap 底层也是使用了哈希表实现的。
------------------|TreeMap 底层也是使用了红黑树数据结构实现的。
迭代器:使用迭代器在迭代的过程中不能使用集合对象修改集合中的元素个数,如果需要修改,要使用迭代器的方法进行修改。
泛型的好处:
1、 把运行时出现的问题提前至了编译期;
2、避免了无谓的强制类型转换;
泛型在集合中的应用:
ArrayList<String>list = new ArrayList<String>(); true
ArrayList<Object>list = new ArrayList<String>(); false
ArrayList<String>list = new ArrayList<Object>(); false
考虑到新老系统的兼容性:
ArrayList list = new ArrayList<String>(); true
ArrayList<String>list = new ArrayList (); true
在泛型中没有多态的概念,两边的数据类型必须要一致。或者是只写一边的泛型类型
推荐使用两边的数据类型要求都写上一致的。
自定义泛型:自定义泛型可以理解为是一个数据类型的占位符,或者可以理解为是一个数据类型的变量。
泛型方法:
泛型方法的定义格式:
修饰符 <声明自定义泛型>返回值类型 函数名(形参列表...){
}
注意:
1、在方法上的自定义泛型的具体数据类型是调用该方法的时候传入实参的时候确定的。
2、自定义泛型使用的标识符只要符合标识符的命名规则即可。
泛型类:
泛型类的定义格式:
class类名<声明自定义的泛型>{
}
注意的事项:
1、在类上自定义的泛型的具体数据类型是在创建对象的时候的指定的;
2、在类上自定义了泛型,如果创建该类的对象的时候,没有指定泛型的具体类型,那么默认是Object类型。
泛型接口:
泛型接口的定义格式:
interface 接口名<声明自定义的泛型>{
}
在接口上自定义泛型要注意的事项:
1、在接口上自定义泛型的具体数据类型是在实现该接口的时候指定的。
2、如果一个接口自定义了泛型,在实现该接口的时候没有指定具体的数据类型,那么默认是Object类型.
IO解决问题:解决设备与设备之间的数据传输问题。比如:硬盘--à内存,内存---à硬盘
字节流:
输入字节流:
-------------|InputStream 所有输入字节流的基类。抽象类
--------------------|FileInputStream 读取文件的输入字节流。
--------------------|BufferedInputStream 缓冲输入字节流。该类内部其实就是维护了一个8kb字节数组而已。该类出现的目的:是为了提高读取文件数据的效率。
输出字节流:
-------------|OutputStream 所有输出字节流的基类。抽象类
--------------------|FileOutputStream 向文件输出数据的输出字节流
--------------------|BufferedOutputStream 缓冲输出字节流。该类出现的目的:是为了提高向文件写数据的效率。该类内部其实也是维护了一个8kb的字节数组而已。
什么情况使用字节流?
读取到数据不需要经过编码或者解码的情况下,这时候使用字节流。比如:图片数据
字符流= 字节流+ 编码(解码)
字符流:
输入字符流:
-------------|Reader 所有输入字符流的基类。抽象类
--------------------|FileReader 读取文件字符的输入字符流
--------------------|BufferedReader 缓冲输入字符流。该类出现的目的是为了提高读取文件字符的效率并且拓展了功能(readLine()),它内部其实就是维护了一个8192个长度的字符数组。
输出字符流:
-------------|Writer 所有输出字符流的基类。抽象类
--------------------|FileWriter 向文件输出字符数据的输出字符流。
---------------------------|BufferedWriter 缓冲输出字符流。该类出现的目的是为了提高写文件字符的效率并且拓展了功能(newLine())。
什么情况下使用字符流?
如果读写的都是字符数据,这时候我们就使用字符流。
转换流:
输入字节流的转换流:输入字节流---------------à输入字符流
InputStreamReader
输出字节流的转换流:
OutputStreamWriter
转换流的作用:
1、 可以把对应的字节流转换成字符流使用;
2、 可以指定码表进行读写文件的数据
FileReader,FileWriter 这两个类默认使用的是gbk编码表。不能由你来指定码表读写文件数据
线程:
多线程的好处:多线程解决了在一个进程中同时可以执行多个任务代码的问题
自定义线程的创建方式:
方式一:继承Thread
1、 自定义一个类继承Thread类;
2、 重写Thread的run方法,把自定义线程的任务自定义在run方法上;
3、 创建Thread子类的对象,并且调用start方法启动一个线程。
方式二:实现Runnable接口
1、 自定义一个类实现Runnable接口;
2、 实现Runnable接口中的run方法,把自定义线程的任务代码定义在run方法上
3、 创建Runnable实现类的对象;
4、 创建Thread对象,并且把Runnable实现类的对象作为参数传递;
5、 调用Thread对象的start方法开启线程。
线程安全问题的解决方案:
线程安全问题出现的根本原因:
1、 必须要存在两个或者两个以上的线程共享着一个资源。
2、 操作共享资源的代码必须有两句或者两句以上。
1、 同步代码块:
synchronized(锁){
需要被同步的代码…
}
2、同步函数:
修饰符 synchronized 返回值类型函数名(形参列表…){
}
注意:
1、 同步代码块的锁可以是任意的对象。同步函数的锁是固定的,非静态函数的锁对象是this对象。静态函数的锁对象是class对象。
2、 锁对象必须是多线程共享的对象,否则锁不住
3、 在同步代码块或者是同步函数中调用sleep方法是不会释放锁对象的,如果是调用了wait方法是会释放锁对象的。
junit(单元测试框架)
目前存在的问题:
1、目前的方法如果需要测试,都需要在main方法上调用;
2、目前的结果都需要人工对比
junit要注意的细节:
1、如果使用junit测试一个方法的时候,在junit窗口上显示绿条,那么代表测试正确,如果是出现了红条,则代表该方法测试出现了异常不通过。
2、如果点击方法名、类名、包名、工程名运行junit分别测试的是对应的方法、类、包中的所有类的test方法、工程中的所有test方法。
3、@Test测试的方法不能是static修饰的与不能带有形参;
4、如果测试一个方法的时候,需要准备测试的环境或者是清理测试的环境,那么可以@Before、@After、@BeforeClass、@AfterClass这四个注释。
@Before、@After是在每个测试方法测试的时候都会调用一次,@BeforeClass、@AfterClass是在所有的测试方法之前与测试之后调用一次而已。
junit使用规范:
1、一个类如果需要测试,那么该类就应该对应着一个测试类,测试类的命名规范:被测试类的类名 + Test
2、一个被测试方法一般对应着一个测试的方法,测试的方法的命名规范是:test + 被测试的方法的方法名
内省----->一个变态的反射
内省主要解决的问题:把对象的属性数据封装到对象中。
BeanUtils:
BeanUtils主要解决的问题:把对象的属性数据封装到对象中。
BeanUtils的好处:
1、BeanUtils设置属性值的时候,如果属性是基本数据类型,BeanUtils会自动帮我们转换数据类型;
2、BeanUtils设置属性值的时候,底层也是依赖于get或者set方法设置以及获取属性值的;
3、BeanUtils设置属性值的时候,如果设置的属性是其他的引用类型数据,那么这时候必须要注册一个类型转换器
BeanUtils使用的步骤:
1、 导包commons-logging.jar、commons-beanutils-1.8.3.jar
如果经常会发生变化的数据我们可以定义在配置文件上。比如说:数据库的用户名与密码。
配置文件的的路径应该如何写?
绝对路径:一个文件的完整路径信息,一般绝对路径是包含盘符的。绝对路径的缺陷:因为绝对路径是有盘符开头的,有些系统是没有盘符的。
相对路径:相对路径是相对于当前程序的路径,当前路径就是执行java命令的时候控制台所在的路径。
类文件路径:类文件路径就是使用了classpath的路径找对应的资源文件。
如果需要使用类文件路径,首先先要获取到一个class对象