1
java特点:面向对象,简单的,分布式的,健壮的,安全的,平台无关的,可移植的,解释性的,高性能的,多线程的,动态的。
![](https://i-blog.csdnimg.cn/blog_migrate/6fa38dbeadf870fe42b4f13f880e9bc0.png)
2 Java开发环境搭建 重点
安装JDK1.8版本:
安装需要注意:安装目录不要有中文,空格,特殊字符。将跟java相关的所有程序安装到同一目录,
这样做好处是,便于管理。
配置环境变量:
Java_home : D:\Program Files\Java\jdk1.8.0_131 变量值是JDK 安装根目录
Path: ;D:\Program Files\Java\jdk1.8.0_131\bin;
Classpath: .;D:\Program Files\Java\jdk1.8.0_131\lib;
如何验证是否安装成功JDK,在cmd中 输入 java -version 指令 成功显示版本。
JDK包含以下常用类库。
java.lang: 系统基础类库,其中包含字符串string等。
java.io:输入输出类库
java.net: 网络相关类库,例如进行网络通信会用到其中的类。
java.util:系统辅助类库,编程中经常用到的集合属于这个类库。
java.sql:数据库操作类库,连接数据库、执行SQL语句、返回结果集需要用到该类库。
java.servlet: JSP/Servlet等使用到的类库,是Java后台技术的核心类库。
Java程序概述:
1.Java源文件以java为扩展名。源文件的基本组成部分是类(class)。
2.一个源文件中最多只能有一个public类,其他类的个数不限,如果源文件包含一个public类,则该源文件必须以public类名命名。
3.Java语言严格区分大小写。
4.Java程序由一条条语句构成,每个语句以分号结束。
基本数据类型分为四种:整型、浮点型、字符型和布尔型。
类型转换:1.自动类型转换:注意 当 byte 型和 short型 之间 进行运算时 ,结果默认为 int型,默认自动类型转换
自动类型转换,将存储范围小的数据类型赋值给存储范围大的数据类型时,可以自动类型转换。
![](https://i-blog.csdnimg.cn/blog_migrate/c520219aabac745a0bca6d9587d045ab.png)
// &与&& 之间的区别 : &&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式(|和||同理(或))
// &还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作
4.1方法的定义
定义:方法是完成某个功能的独立代码块。
语法: [修饰符] 返回值类型 方法名称([形参列表]){
方法体
}
在类内部调用方法很简单,只需给出方法名以及方法的实际参数列表(实参列表的数据类型必须与形参列表一致或可以自动转换成形参列表的格式)即可。如果方法有返回值,则可以赋值给相应类型的变量。
形参列表:执行方法所需要的值,通过形参列表来传入方法中,形参可以有多个值,也可以没有参数。
但()括号必须保留
方法好处: 1代码重复利用。2 便于维护。3 便于扩展。4 程序结构更加清晰
方法递归调用
定义:递归调用就是在方法内部调用方法本身。
需求:完成某数的阶乘
public class Test02 {
public static void main(String[] args) {
int n=3;
System.out.println(factorial(n));
}
static int factorial(int n){
if(n==1){
return 1;
}
int sum=factorial(n-1);
return sum*n;
}
}
4.2一维数组
数组的作用:存储一组相同数据类型的数据。缺点:数量固定。类型相同。引用类型无方法。
创建数组语法:
1 数组的声明
数据类型 [] 数组名 ,或 数据类型 数组名 []。
2 创建数组
数组名 = new 数据类型[数组长度];
3声明并创建数组
数据类型 []数组名 =new 数据类型 [数组长度];
4声明并创建初始化数组:
数据类型 []数组名={值1,值2,........};
5向数组中添加数据
数组名[下标]=数据;
6获取数组中的数据
数组名[下标]
创建数组在内存中的结构
4.2.2值传递和引用传递
值传递传递的是数据的副本,所以传递后所做的修改不会影响原来的数据。
引用传递传递的是地址的副本,所以传递后所做的修改会影响原来的数据。
4.2.3排序
相关概念: 1、时间复杂度、时间复杂度可以认为是对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。常见的时间复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n), 线性对数阶O(nlog2n),平方阶O(n2) // 时间复杂度O(1):算法中语句执行次数为一个常数,则时间复杂度为O(1)
2、空间复杂度 // 空间复杂度是指算法在计算机内执行时所需存储空间的度量,它也是问题规模n的函数 // 空间复杂度O(1):当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1) 空间复杂度O(log2N):当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为O(log2n) ax=N,则x=logaN, 空间复杂度O(n):当一个算法的空间复杂度与n成线性比例关系时,可表示为0(n).
冒泡排序:最好:O(N) 最坏:O(N2) 平均:O(N2) 空间复杂度o(1) 稳定简单
public class Test09 {
public static void main(String[] args) {
int []a={3,2,1,5,4};
for(int i=1;i<a.length;i++){//外循环控制比较的轮数
for(int j=0;j<a.length-i;j++){//内循控制每轮比较的次数
if(a[j]>a[j+1]){ //如果下面的数大于上面的数就交换位置
int tmp=a[j+1];
a[j+1]=a[j];
a[j]=tmp;
}
}
}
System.out.println("打印输出排序后的数组");
// for(int i=0;i<a.length;i++){//外循环控制比较的轮数
// System.out.println(a[i]);
// }
//增强for循环
for(int n:a){
System.out.println(n);
}
}
}
选择排序
//选择排序
public class SelectionSort {
public static void main(String[] args) {
int a[] = {1, 3, 5, 7, 89, 3, 5, 6, 7, 8, 9, 24, 4365, 234, 24, 3};
//选择
for (int i = 0; i < a.length; i++) {
//默认第一个元素是最小值
int min = a[i];
//记录最小下标
int index = i;
//通过与后面数据进行比较得出最小值和下标
for (int j = i + 1; j < a.length; j++) {
if (min > a[j]) {
min = a[j];
index = j;
}
}
//然后将最小值与本次循环的开始值交换
int temp = a[i];
a[i] = min;
a[index] = temp;
}
for (int e : a) {
System.out.println(e);
}
}
}
插入排序
//插入排序
public class InsertionSort {
public static void main(String[] args) {
int a[] = {1, 3, 5, 7, 89, 3, 5, 6, 7, 8, 9, 24, 4365, 234, 24, 3};
//插入排序
for (int i = 1; i < a.length; i++) {
//从外层循环第二个开始比较
for (int j = i; j > 0; j--) {
if (a[j] < a[j - 1]) {
int temp = a[j];
a[j] = a[j - 1];
a[j - 1] = temp;
} else {
break;
}
}
}
for (int n:a){
System.out.println(n);
}
}
}
4.3二维数组
创建数组语法:
1 数组的声明
数据类型 [][] 数组名 ,或 数据类型 数组名 [][]。
2 创建数组
数组名 = new 数据类型[行数][列数];
3声明并创建数组
数据类型 [][]数组名 =new 数据类型 [行长度][列长度];
4声明并创建初始化数组:
数据类型 []]数组名={{值1,值2...},{值1,值2...},{值1,值2...}};
String字符串
5.1、定义:String 类表示字符串类。String 对象是特殊的。
1.String 是常量。一旦赋值不可修改。
2.String 是最终类,不可被继承。
5.2、连接字符串:使用“+”进行String字符串连接
比较字符串:使用“==”比较两个字符串,是比较两个对象的地址是否一致,本质上就是判断两个变量是否指向同一对象,如果是则返回true,否则返回false。而String类的equals方法则是比较两个String字符串的内容是否一致,返回值也是一个布尔类型。
5.3.String类的常用方法:
public char charAt(in index) 从字符串中反回指定索引处的字符值
public int length() 返回此字符串长度
public int indexOf(String str) 返回指定子字符串在此字符串中第一次出现处的索引
public int indexOf(String str,int fromIndex) 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始搜索。
5.4. String与StringButter区别
1 String 类一旦赋值不可改变,使用final修饰的.
3 StringBuffer比String速度快。因为在频繁操作String类时它会重新开辟空间,所以执行速度慢。
总结:StringBuffer线程安全,StringBuilder线程非安全。
StringBuilder比StringBuffer速度快。
对于三者使用的总结:
1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
6.1类定义
:对某一类事物的抽象描述,包括这类事物的属性和行为。
面向对象的基本特征: 封装、继承、多态。(抽象)
对象:某一类事物的具体实例。类是Java程序的基本单元。Java是面向对象的程序设计语言,所有程序都是类组织起来的。
方法:在面向对象的编程中,将这些对象的属性仍然成为属性,将对象具有的行为称为方法。
注解:class关键字后面是要定义的类的名称,然后有一对大括号,括号内写的就是类的主要内容。
类的主要内容分为两部分:第一部分是类的属性定义。类的属性其实就是成员变量。第二部分是类的方法的定义,描述类具有的行为,这些方法也称为成员方法。(类里没有main()方法只能编译,不能运行) 。在未
给对象属性赋值前使用属性时,如果该属性为引用数据类型,其初始默认值为null,如果该属性是int型,其初始默认值为0.
6.2封装:封装就是将抽象得到的属性和行为结合起来,形成一个有机的整体就是类。目的:增强安全性和简化编程。
良好的封装:是通过使用private对属性进行封装,从而保护信息安全。使用public修饰方法时,外界可调用该方法。通常将私有属性的值和获取私有属性值的方法称为setter和getter方法。
总结:类的属性私有化提供公共的访问方法,目的在于保护数据,增强安全性。
6.3构造方法:
作用:创建对象。完成对象的初始化工作,它能够把定义对象时的参数传给对象。
属性(成员变量)初始化情况:1.创建对象时默认初始化成员变量2.定义类时,给成员变量赋初值。3.调用构造方法时,使用构造方法所带的参数初始化成员变量。
构造方法调用: 实例化对象时通过 new关键字调用构造方法。
构造方法(构造函数)特点:1.构造方法的方法名必须与类名相同。2.构造方法没有返回值类型,也不能定义为void,在方法名前不声明返回值类型。
构造方法定义:public 类名([参数列表]){
代码块。
}
构造方法的使用:
6.4对象初始化过程
在使用new关键字创建并初始化对象的过程中,具体的初始化分为4步。
1.给对象的实例变量分配空间,默认初始化成员变量。
2.成员变量声明时的初始化。
3.初始化块初始化
4.构造方法初始化
注:初始化块可以用来初始化类的成员变量。初始化块初始化成员变量的顺序是在默认初始化成员变量以及成员变量声明时赋值之后,在使用构造方法初始化之前。
对象初始化内存结构图
![](https://i-blog.csdnimg.cn/blog_migrate/b724ba42ffa8e649f154a728239d6776.png)
6.4重载
定义:在同一个类中,可以有两个或两个以上的方法具有相同的方法名,但他们的参数列表不同。在这种情况下,该方法就被称为重载(overload)。
参数列表不同包括以下三种情形:1.参数的数量不同2.参数的类型不同3.参数的顺序不同。
注意:仅返回值不同的方法不叫重载方法。重载方法之前没有任何关系。只靠传入参数的不同确定调用那个方法。
7.2 权限
public 公共的公开在整个工程中,任何类都可以访问
protected:保护权限访问范围,同类、同包。不同包的子类
default 默认权限,同类、同包中可以使用
private 私有权限 只能在本类中使用
权限修饰符可以修饰:类、成员变量(实例变量)、方法、数组等
7.3 static关键字(修饰成员变量、方法)
1、静态成员变量是属于类,类的所有对象共享。
2、静态方法中不能直接使用非静态成员变量。
3、非静态成员变量是属于对象的。每个对象的非静态属性是不同的。
访问非静态成员变量:对象名.属性名
访问静态成员变量: 对象名.静态属性名 类名.静态属性名(建议使用)
访问非静态方法: 对象名,方法名
访问静态方法:对象名.方法名 类名.方法名(建议使用)
静态块:执行时机:第一次访问类的时候,会首先执行静态块,然后执行初始化块,最后执行
构造方法。静态块只执行1次。
8.1 抽象和封装
继承:使用已经存在的类作为基类,创建新类的技术。使用extends 继承一个类,且只能继承一个类。
注意:所有的默认继承Object类。实例化子类时首先会自动调用父类无参构造方法。
继承和访问权限:1、子类可以继承父类中访问修饰为public 和 protected 的属性和方法。
2 、子类可以继承父类中访问权限为默认的属性和方法,但子类必须和父类在同包中。
3 、子类无法继承父类中访问权限为private 的属性和方法。
4 、子类无法继承父类中的构造方法。
但是可以在子类中调用,通过super调用
super:Super()用来调用父类的构造方法。根据所传参数决定调用的是父类的那个构造方法。根据参数
自动匹配。
注意:必须是在第一行调用
重写:子类继承父类,子类中方法的定义与父类中相同。那么子类重写(覆盖)了父类中的方法。
注意:在没有重写父类方法之前,子类对象调用的方法是父类中定义的方法。一旦子类重写父类中的方法,
子类对象调用的方法就是子类重写的方法。
8.2 多态
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
多态的形式:向上转型:弊端 无法调用子类自己独有的方法。
向下转型:弊端需要类型转换 ,容易出错,利用instanceof 判断是否 是某一个类的对象。然后进行转换。
多态的好处:1.可扩展性 2. 可扩充性 3.灵活性
9.1
抽象类:抽象类语法:[修饰符] abstract class 类名{ }
抽象类的特征:1、抽象类不能被实例化
2、抽象类的子类必须实现抽象方法,除非子类也是抽象类
3、抽象类可以普通方法,也可以有抽象方法,但一个类中如果有抽象类,此类必须是抽象类。
定义抽象类的目的:类自身没打算实例化,只为让子类继承,抽象类中的抽象方法子类必须重写,除非子类也是抽象的。
final关键字:1、final修饰类:final修饰类即表示此类已经是“最后的、最终的含义”。因此被final修饰的类不能被继承,即不能拥有自己的子类。
2、final修饰方法:final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写 (可以重载多个final修饰的方法。)
3、final修饰变量:final修饰的变量表示此变量是“最后的、最终的”含义。一旦定义了final变量并在首次为其显示初始化后,final修饰的变量值不可被改变。
问题:面向对象常见问题(重写,toString equals 多态 抽象类)
1
为什么要重写
toString
equals
方法?
答:什么是重写:子类继承父类,子类中定义的方法和父类中定义的方法相同,但方法体不同,那么我们说子类重写了父类的方法 。
为什么重写toString 方法,因为在父类中(Object)toString方法是返回本对象内存中的地址,如果我们想返回本来的详细信息就需要重写。
为什么要重写equals方法,因为在父类中(Object)类中 equals方法只是做了==判断两个对象,这种做法不能满足我们判断两个对象是否相等的要求。所以要重写。
2. 重写equals方法,在方法中都干什么?
1、判断两个对象的地址是否相同
2、判断传入的对象是否为空
3、判断两个对象看是否是同一个类
4、对两个对象中的属性逐个比较,如果是引用类型,调用自身equals方法,如果是基本数据类型,用==比较。
3
何为多态?
必要条件:要继承,重写。
向上转型,向下转型:父类引用指向子类实例,调用方法是子类自己重写的方法。
向上转型弊端:无法调用子类自身独有的方法,这就需要向下转型。
向下转型弊端:类型转换出现类不匹配。(类型转错了),转之前要先判断使用
instanceof关键字判断类型。
多态好处:1.可替换性2.可扩充性3.灵活性
9.2 接口
什么是接口:接口就是定义标准和规范。
接口中定义的语法:[修饰符] interface 接口名称{ }
实现类通过 implements 关键字实现接口。
接口中可以定义的内容:
1、公共静态常量 例如:public static final double i=3.0;
2、公共抽象方法 例如:public abstract void show();
3、JDK8支持 在接口中写静态方法
4、JDK8支持在接口中定义静态内部类
必须知道接口的特性:
1.接口不可以被实例化
2.实现类必须实现接口的所有方法
3.实现类可以实现多个接口
4.接口中的变量都是静态常量
5.接口可以继承接口
注意:一个类可以实现多个接口,解决了类单继承的问题。
1.1异常概述
在程序运行过程中,经常会出现一些意外情况,这些意外情况会导致程序出错或者崩溃,从而影响程序的正常执行,如果不能很好的处理这些意外,程序的稳定性就会受到质疑。在java中这些意外称为异常。出现异常时的处理称为异常处理。
异常的分类:所有的异常都继承自java.lang.Throwable类,Throwable类有两个直接子类,Error类和Exception类。
Error类:是Java应用程序本身无法恢复的严重错误,应用程序不需要捕获、处理这些严重错误。当程序发生这种严重错误时,通常的做法是通知用户并中止程序的执行。
Exception类:分为运行时异常(RuntimeException)和检查时异常(CheckedException)两种。
![](https://i-blog.csdnimg.cn/blog_migrate/089b5773e07df2bf264af74bc8064f7e.png)
1.3异常捕获顺序Java程序采用了try...catch...finally结构对异常进行处理。在捕获异常时应该按照“从小到大”的顺序捕获异常,这样才能保证逐层捕获,从而避免父类的大的异常进行了捕获,导致子类小的异常无法进行捕获的情况。常用的异常对象的方法有两个:一个是printStackTrace(),用于输出异常的堆栈信息。另一个方法是getMessage(),用于返回异常详细信息的字符
常见的异常类:
ClassCastException 对象强制类型转换出错
IllegalAccessException 当前执行方法无法访问指定类、属性、方法、构造方法等
IllegalArgumentException 方法接收到非法参数
InputMismatchException 有Scanner抛出,获取内容与期望类型不匹配
SQLException 关于数据库访问错误或其他错误信息异常
IOException 发生I/O异常时
ArrayStoreException 试图将错误类型的对象存储到一个对象数组时抛出的异常。
ClassNotFoundException 类找不到异常
1.5 手工抛出异常
抛出异常:语法 throw 异常对象;
声明方法抛出异常:就是当方法本身不知道或者不愿意处理某个可能抛出的异常时,可以选择用throws关键字将该异常提交给调用该方 法的方法进行处理。
该方法必须进行声明,调用该方法的方法必须进行处理或再次声明向外抛出。
声明方法:需要在方法的参数列表之后,在方法的大括号前,增加“throws异常列表”进行声明。
例:public
void setAge(
int age)
throws MyException {}
1.6 自定义异常类
Exception类时Java中所有异常类的父类,所以我们定义自定义异常类时,通常继承自该类。
例:public
class
MyException
extends Exception {}
2.1 数据逻辑结构
数据结构从大的方向上分,可以分为
逻辑结构和
存储结构。
逻辑结构分为四类:
集合:数据元素间没有任何关系。
线性结构:数据元素间有线性联系,所谓线性关系是指除第一个元素外,其他元素有且只有一个前驱,除最后一个元素外,其他元素有且只有一个后继。
树结构:数据元素间有层状关系。
图结构:数据元素间有网状关系。
数据:在计算机系统中,各种字母和数字符号的组合、语音、图形、图像等统称为数据。数据又指所有能输入到计算机并被计算机程序处理的符号总称,是用于输入计算机进行处理,具有一定意义的数字、字母、符号和模拟量等的统称。
数据元素:数据元素是数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。
存储结构:数据存储结构通常分为两类,顺序存储结构和链式存储结构。
顺序结构:顺序存储结构是把逻辑上相邻的节点存在物理位置相邻的存储单元里,节点间的逻辑关系有存储单元的邻接关系来体现,由此得到的存储表示称为顺序存储结构。
优点:节省存储空间,增加了访问速度。
缺点:插入、删除元素时速度比较慢。
链式结构:l链式存储结构不要求逻辑上相邻的节点在物理位置上也相邻,节点间的逻辑关系是由附加的指针表示的,由此得到的存储表示称为链式结构。
优点:插入、删除元素时速度比较快。
缺点:存储空间较大,访问速度慢。
线性表的链式存储有三种形式:单链表、循环链表、双向链表。、
栈:栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后进入的数据在栈顶,需要读取数据的时候是从栈顶开始弹出数据(最后一个进入的数据被第一个读出来)。后进先出
队列:队列也是一种特殊的线性结构,它只允许在该结构的前端进行删除操作,在后端进行插入操作。进行插入操作的端称为尾端,进行删除操作的称为队头。队列中没有元素时,称为空队列。(先进先出的线性结构)。
注:栈和队列是线性表的特殊情况,是受限的线性结构,只是在数据结构的操作上有区别。队列:先进先出
3.1 集合
![](https://i-blog.csdnimg.cn/blog_migrate/f3233a78e2113b14d2679bf4c66be040.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6e0aadf2b1e8c89507db6f56f8264346.png)
集合也称容器。它可以将一系列元素组合成一个单元,用于存储、提取和管理数据。
Java集合的框架主要分两大部分,一部分实现了Collection接口,该接口定义了存取一组对象的方法,其子接口Set和List分别定义了存取方式;另外一部分是Map接口,该接口定义了存储一组“键(key)值(value)“映射对的方法。
Collection是最基本的集合接口,一个Collection代表一组Object,每个Object即为Collection中的元素。
Collection接口继承自Iterable接口,因为Iterable接口允许对象称为foreach语句的目标,所以所有集合类都可以称为JDK1.5的新特性增强for循环的目标。
3.2 Set接口方法
Set接口继承自Collection接口的主要方法有:
boolean add(Object obj) 向集合中添加一个数据元素,该元素不能和集合中现有数据元素重复。(equals判断)
void clear() 移除此集合中的所有元素,即将集合清空。
boolean contains(Object obj) 判断此集合中是否包含该数据元素,如包含则返回true。
boolean isEmpty() 判断集合是否为空,为空则返回true。
Iterator iterator() 返回一个Tterator对象,可用它来遍历集合中的数据元素。
boolean remove(Object obj) 如果此集合中包含有该数据元素,则将其删除,并返回true
int size() 返回集合中数据元素个数,注意与数组、字符串获取长度的方法的区别。
Object[] to Array() 返回一个数组,该数组包含集合中的所有数据元素。
3.2 HashSet使用(无序,线程不安全,元素值可以为null)
Set接口主要有两个实现类:HashSet和TreeSet,HashSet类有一个子类LinkedHashSet,它不仅实现了哈希算法,而且采用了链表结构。
TreeSet类在实现了Set接口的同时,也实现了SortedSet接口,是一个局域排序功能Set接口类。
TreeSet集合中的元素按照升序排列,默认是按照自然升序排列,也就是说TreeSet集合中的对象需要实现comparable接口。这是因为TreeSet集合中的元素时String类,而String类实现了Comparable接口,默认按自然排序。
如果程序员想定义自己的排序方式,方法也很简单,就是要让加入的TreeSet集合中的对象所属的类实现Comparable接口,通过实现ComparaTo(Object o)方法,达到排序目的。
3.3 Iterator迭代器
Iterator接口方法的ierator()方法返回一个Iterator对象,通过Iterator接口的两个方法即可实现对集合元素的遍历。
以下列举Iterator接口的三个方法:
boolean hasNext() 判断是否存在下一个可访问的数据元素。
Object next() 返回要访问的下一个数据元素。
void remove() 从迭代器指向的collection集合中移除迭代器返回的最后一个元素。
3.4
增强for循环:又称为foreach循环。借助增强for循环,可以用更简单的方式来遍历数组和Collection集合中的对象。如果使用增强for循环操作集合,无法实现对集合元素的删除,还是需要调用Iterator迭代器的remove()方法才能完成。
3.5 List接口:List接口的集合中,元素时有序的,而且可以重复。List接口和Set接口一样,可以容纳所有类的对象。List接口的常用类有ArrayList和LinkedList.
List接口方法:List接口继承自Collection接口,除了拥有Collection接口所拥有的方法外,它还拥有下列方法:
void add(int index,Object to) 在集合的指定位置插入指定的数据元素。
Object get(int index)返回集合中指定位置的数据元素。
int indexOf(Object o) 返回此集合中第一次出现的指定数据元素的索引,如果此集合不包含该数据元素,则返回-1;
int lastIndexOf(Object o) 返回此集合中最后出现的指定数据元素的索引,如果此集合不包含该数据元素,则返回-1;
Object remove(int index)移除集合中指定位置的数据元素。
ArrayList:在存储方式上采用的是数组进行顺序存储的,ArrayList对数组进行了封装,实现了可变长度的数组。
LinkedList:在存储方式上采用的是链表进行链式存储。
LinkedList接口除了拥有ArrayList接口提供的方法外,还增加了如下一些方法:
void addFirst(Object o) 将指定数据元素插入此集合的开头。
void addList(Object o)将指定数据元素插入此集合的结尾。
Object getFirst() 返回此集合的第一个数据元素。
Object getLast() 返回此集合的最后一个数据元素。
Object removeFirst() 移除并返回此集合的第一个元素。
Object removeLast() 移除并返回此集合的最后一个数据元素。
3.5工具类
Collections:集合对象的工具类,提供了操作集合的工具方法,例如排序、复制和反转排序等方法。
Arrays:是数组的工具类,提供了对数组的工具方法,例如排序、对数组赋值、比较数组元素中的值是否相等、二分查找等。
3.6Map接口:
HashMap和Hashtable的区别
1、HashMap和Hashtable都完成了Map接口;
2、HashMap非线程安全的,而Hashtable是线程安全的,原因是Hashtable里面的方法使用Synchronize关键字修饰的;
3、HashMap可以存入空键或空值,但不能同时为空。
4、Hashtable不可以存空间和空值。
3.7自动拆箱和装箱
1、为什么有包装类型?
java语言是面向对象的语言,但是正因为有了8种基本类型的存在,导致Java不是完全面向对象的语言,为了让java语言完全面向对象,java设计人员封装每一种基本类型 设计基本类型对应的包装类型。
2.包装类型
基本类型:boolean byte short long float double
包装类型:Boolean Byte Short Long Float Double
char Character int Integer
3.基本类型和包装类型的相互转换。
1.基本类型-------->包装类型
(1) Integer integerI=new Integer(10);
(2)Integer integer=10;//JDK5.0新特性 自动装箱Auto-boxing
自动装箱:把基本类型直接赋值给包装类型 会自动转换成包装类型叫做自动装箱。
2.包装类型--------->基本类型
(1)包装类型对象.xxxValue() intValue() doubleValue()
/* Integer integerI=new Integer(10);
int i=integerI.intValue();
*/
(2)自动拆箱
/* Integer integerI=new Integer(10);
int i=IntegerI;//自动拆箱 Auto-unboxing
3.基本类型----------->字符串
String s=String.valueof(10);
2 定义泛型类
问题:要求编写坐标类,设置坐标X Y。
1.要求保存的坐标类型可以是int型。
2.要求保存的坐标类型可以是double型
3.要求保存的坐标类型可以是String型
3通配符用法
问题:一个方法形参类型 无法确定时如何解决?因为形参类型是泛型,
所以无法确定传入的参数是什么类型。这是就需要用到 通配符“?”来解决这一问题,
4 ?extends 类 设置泛型上线
?
extends
设置泛型上线可以在声明上和方法参数上使用。
class Point3<T extends Number>
?super类 设置泛型下线,方法参数上使用:
?Super 类 在方法参数上使用,设置泛型下线。
//设置通配符 类型下线只能是String类型
public static void fun(Point4<? super String>p)
泛型接口:第一种形式:泛型接口的实现类也是泛型。
public interface IMessage<T>
public class MessageImpl<T> implements IMessage<T>
第二种形式:实现接口的类不去指定泛型,而是将接口泛型确定具体类型。
public class MessageImpl2 implements IMessage<String>泛型方法:
//无返回值泛型方法
public <T> void fun(T t){
System.out.println(t);
}
//有返回值泛型方法
public <T> String fun2(T t){
return "";
}
泛型总
1 泛型解决的是向下转型所带来的安全隐患问题,其核心组成就是在定义类或接口的时候
不设置参数或属性的类型。
2 ?可以接收任意泛型类型,只能够取出但是不能够修改。
File
类对象代表一个特定的文件或目录。提供了若干方法对这些文件或目录进行操作
常用方法:
exists
()//
测试此抽象路径名表示的文件或目录是否存在。
isFile
()//
测试此抽象路径名表示的文件是否是一个标准文件
isDirectory
()
//
测试此抽象路径名表示的文件是否是一个目录。
字节流类:所有的字节流类都继承自
InputStream
和
OutputStream
着两个抽象类。
字符流类:
所有的字符流都继承自着两个抽象的父类Reader和Writer
单例模式:singleton是一种创建模型,指某个类采用了singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点
。
volatile的主要作用是:提示编译器该对象的值有可能在编译器未监测的情况下被改变。
核心知识点如下:
1.将采用单例设计模式的类的构造方法私有化
2.在其内部产生该类的实例化对象,并将其封装成private static类型
3.定义一个静态方法返回该类的实例
最优方案:(线程安全并且效率高)
public
class singletonTest {
private singletonTest() {
}
private
static
volatile singletonTest
instance;
public
static singletonTest getInstance() {
if (
instance ==
null) {
synchronized (singletonTest.
class) {
if (
instance ==
null) {
instance =
new singletonTest();
}
}
}
return
instance;
}
}
装饰者设计模式
1、 装饰者模式,动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承
更加有弹性的替代方案。
2、组合和继承的区别
继承:继承是给一个类添加行为的比较有效的途径。通过使用继承,可以使得子类在
拥有自身方法的同时,还可以拥有父类的方法。但是使用继承是静态的,在编译的时
候就已经决定了子类的行为,我们不便于控制增加行为的方式和时机。
组合
:组合即将一个对象嵌入到另一个对象中,由另一个对象来决定是否引用该对象
来扩展自己的行为。这是一种动态的方式,我们可以在应用程序中动态的控制。
与继承相比,组合关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,
可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。
3
、装饰者模式的优缺点
优点
1、装饰者模式可以提供比继承更多的灵活性
2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器
,从而实现不同的行为。
3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同
行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对
象。
4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件
类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
缺点
1、会产生很多的小对象,增加了系统的复杂性
2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错
,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较
为烦琐。
4
、装饰者的使用场景
1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。 当不能
采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
什么是反射机制?
Java反射就是Java程序在运行时,可以加载、探知、使用编译期间完全未知的类。
也就是说,Java程序可以加载一个运行时才得知类名的类,获得类的完整构造方法,并实例化处对象,给对象属性设定值或者调用对象的方法。这种在运行时动态获取类的信息以及动态调用对象的方法的功能称为Java反射机制。
反射类的作用:1.反编译 2.通过反射机制访问Java对象的属性,方法,构造方法等。
创建反射类的方式:1. Object类中的 getClass()方法
2. 类名.class
3. Class.forName("java.lang.String");
获得反射类对象的方式:
Class
c
=
stu
.getClass();
Class
cc
=Student.
class
;
Class
ccc
=Class.
forName
(
"org.lanqiao.pojo.Student"
);
Student stu=(Student)ccc.newInstanse();//通过反射类对象,创建该类的实例对象
Class类继承自Object类,是Java反射机制的入口,封装了一个类或接口运行时信息,通过调用Class类的方法可以获取这些信息。
Class类的常用方法:
(Field属性类)Field[]getFields();//所有公共属性(含继承公共属性)getDeclaredFields返回所有属性(不含继承属性);
(Method方法类)Method[]Methods();//所有公共方法(含继承公共方法)
(Constructor构造方法)Constructor[]getConstrutors();//返回该类的所有公共构造方法 构造方法不能被继承
T.newInstance()
;//使用无参构造方法创建该类的一个新实例;
修改属性:
通过属性名得到属性对象
Field
f
=
ccc
.getDeclaredField(
"s"
);
//
设置属性的访问权限
f
.setAccessible(
true
);
//
设置属性的值
f
.set(
stu2
, 20);
//
获取属性的值参数的获取的那个对象的属性值
System.
out
.println(
f
.get(
stu2
));
//
通过调用私有属性的公共方法来获取属性值
System.
out
.println(
stu2
.getS());
动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。可以给这个类创建一个代理,故名思议就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强。
动态代理实现:首先必须定义一个接口,还要有一个InvocationHandler(将实现接口的类的对象传递给它)处理类。再有一个工具类Proxy(习惯性将其称为代理类,因为调用他的newInstance()可以产生代理对象,其实他只是一个产生代理对象的工具类)。利用到InvocationHandler,拼接代理类源码,将其编译生成代理类的二进制码,利用加载器加载,并将其实例化产生代理对象,最后返回。
动态代理的应用:Spring的AOP,加事务,加权限,加日志。
6 多线程
线程状态:
1、新建状态:当用new操作符创建一个线程时,线程还没有开始运行线程中的代码,此时线程处在新建状态。
2、就绪状态:当线程对象调用start()方法即启动了线程,等待调度程序(thread scheduler)分配CPU时间的状态。
3运行状态
(Running): 当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.
4.
阻塞状态
(Blocked):所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
进入
阻塞状态的原因
:
1>
线程通过调用
sleep
方法进入睡眠状态;
2>
线程调用一个在
I/O
上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
3>
线程试图得到一个锁,而该锁正被其他线程持有;
4>
线程在等待某个触发条件;
......
5.
死亡状态
(Dead): 1) run方法正常退出而自然死亡 2) 一个未捕获的异常终止了run方法而使线程猝死。
Java
中创建线程主要有三种方式:1.继承Thread类2.实现Runnable接口3.创建Callable接口的实现类(有返回值)
一、继承
Thread
类创建线程类
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程
要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。
二、通过
Runnable
接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体
同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对
象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。
三、通过
Callable
和
Future
创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行
体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask
对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
线程终止的三种情况:
1 线程正常执行结束。
2 线程抛出异常且未被捕获。
3 线程调用stop()方法终止线程,该方法已经过期。不建议使用
线程方法:
sleep():让线程进入睡眠等待一段时间,线程进入阻塞状态,时间过后进入就绪状态。
interrupt():让当前线程终止等待,进入就绪状态
。
Join():让当前线程等待加入的线程完成后才能继续执行
setPriority():
设置线程优先级,最高10,最低1,默认5.
setDaemon(true):守护线程必须在调用start()方法之前,设置守护线程,当程序中只有守护程序时,该程序运行结束。
线程锁关键字:synchronized (同步)
定义锁对象:
static
final
Object
lock
=
new
Object();
对lock对象上锁:
synchronized(lock);
对方法上锁:
private
static
synchronized
void
doTask
(
int
tid
)
解决线程死锁:
多个线程上锁的顺序要一致。
线程协作:
void wait(): 当前线程等待,等待其他线程调用对象的notify()或notifyAll()方法
void notify():唤醒在此对象锁上等待的单个线程
void notifyAll():唤醒在此对象锁上等待的所有线程
线程池的作用:
1.提高程序的执行效率
2.控制线程的数量,防止程序崩溃
创建线程池的常用方法:
ForkJoinPool:作用充分挖掘利用多核CPU的能力,把一个大任务分解成多个小任务,执行完后再行合并。
![](https://i-blog.csdnimg.cn/blog_migrate/d28e5302245c0b2b30011ac5e6453678.png)
线程池的使用方法:
1、创建一个线程池
2、创建一个Runnable对象
3、将Runnable对象作为线程任务提交到线程池中,调用线程池的submit或excute方法
4、使用完线程池后,调用线程的shutdown()方法关闭线程池(不会立马关闭 先执行完线程池中的所有已提交任务后 依次关闭线程对象 所有的线程对象进入死亡状态)
注:shutdownNow();//试图停止正在执行的线程任务,暂停正在等待的任务..但这是试图,也不一定立马关闭。
线程池的submit和excute方法的区别:
1、接收的参数不一样
2、submit有返回值,而execute没有
3、submit方便Exception处理
程序架构:
1 、C/S架构程序:(Client/Server) 分为客户端和服务器端,一般写两套程序。
2、 B/S架构程序:(Browser/Server) 分为浏览器和服务端,写一套程序,客户端通过浏览器访问服务器端。
C/S结构程序分两类:
TCP程序:是采用可靠的连接方式进行传输
UDP程序:不可靠连接属于数据报协议
注解
内建注解(基本注解):
@Override
:限定重写
@Deprecated
:标记过时
@SuppressWarnings
:抑制编辑器警告
元注解:
@Target 指定被修饰的注解能修饰哪些程序元素
@Retention
用于指定被修饰注解可以保存多少时间
@Document 使用该注解修饰的程序元素的API文档中都将包含该注解的说明
@Inherited 用于子类注解继承父类注解
函数式接口:一个接口中,只能有一个方法;
Lambda表达式只能应用于函数式接口。