Java笔记(提高篇)整理
主要内容:
面向对象
异常
数组
常用类
集合
IO流
线程
反射
Socket编程
1. 面向对象
1.1包
用来管理Java中的类, 类似文件夹管理文件一样。
因为同一个包中不能出现同名的类, 不同包中的类名可以相同, 所以包可以解决类名命名冲突问题
Java提供了若干的类, 分别放在不同的包中, 本阶段可能使用的包:
Java.lang 是Java语言的基础包,系统自动导入,其中的类可直接调用,如System,String
Java.util 包含若干工具类,如Scanner
Java.io 输入输出相关的类
Java.net 网络相关的类
1.1.1 定义包
使用package定义包
package 包名;
1) package是关键字, 用来定义包的
2) 包名命名规则: 公司域名倒序.项目名.模块名
如com.bjpowernode.demo01所有字母必须小写
3) 定义包的语句必须作为文件的第一条语句
4) 如果把某个类放在包中, 类的完整类名为: 包名.类名
com.bjpowernode.day01.sub01.Hello
在程序运行时, java命令跟完整类名
5) 在编译时, 可以使用-d参数指定字节码的存储位置,如:
javac -d . Hello.java
小点指定把生成的字节码文件保存到当前目录中
系统会在当前目录中依次创建与包名对应的文件夹.
1.1.2使用其他包中的类
在一个包中,可以使用其他包中的类, 要求被使用的类必须是公共类
1) 直接使用完整类名访问
2) 可以先import导入该类, 直接使用类名即可
1.2 Eclipse
1) 工作区
2) 透视图
3) 创建项目
Eclipse中类不能单独运行必须添加在项目中
4) 添加类
5) 运行
6) 设置字号
7) 设置文件编码格式
8) 添加智能提示
9) 当前项目中添加现有的类
1.直接把源文件 MyUtil.java 复制到src 包中, 可能会需要创建与源文件对应的包
2. 直接复制源代码到Src包中,系统会自动的创建对应的包与源文件
10) 导入已有的项目
注意:同一工作区中不能有项目名相同的项目
11) 乱码问题
文件保存时使用的编码格式与打开时的编码格式不兼容
1.3 访问权限
1.3.1类的访问权限
公共类和非公共类
类的访问权限修饰符只有一个:public
什么情况下把类修饰为公共类?
如果定义的类想让别人使用就定义为public公共类
1.3.2类成员的访问权限
访问权限 |
当前类 |
当前包 |
派生类(不在当前包中) |
其他包 |
私有的(private) |
能 |
No |
No |
No |
默认的(没有修饰符) |
能 |
能 |
No |
No |
受保护的(protected) |
能 |
能 |
能 |
No |
公共的(public) |
能 |
能 |
能 |
能 |
定义类成员时,如何选择访问权限??
遵循权限最小化原则
1.3.3方法覆盖的访问权限
方法覆盖(重写)规则:
1) 方法签名必须一样,方法签名就是方法名和参数列表
2) 返回值类型如果不是引用类型必须一样,是引用类型可以相同,子类型的返回值类型可以是父类方法返回值的子类型
3) 访问权限,子类的访问权限可以更宽泛
如果用public修饰,子类必须使用public修饰
若使用protected修饰,子类可以用public/protec修饰
若父类默认修饰符修饰,
若在同一个包中,可用protected /public修饰,也可默认修饰
不在同一个包中则不能覆盖。
4)子类不能抛出比父类更多的异常
1.4Object 类
Java类中的继承是可传递的
Object类是所有类的根父类,Java中的类要么直接继承Object,要么间接继承
Object类中定义的所有实例方法,所有对象都可以调用
|
1) clone() 对象的克隆
是指在堆中在创建一个与原来对象完全一样的对象
需要在子类中重写该方法才能实现。
2) finalize()
当垃圾回收器回收某个对象时,会执行该方法
Java中垃圾回收时间不确定,该方法执行时间不确定
final finalize finally
3) getClass()
返回对象所对应的运行时类
4) notify()/wait()
和线程有关
5) toString()
使用System.out.println(obj)打印obj对象时,会调用obj对象的toString(),若该toString()继承自object类,默认打印的是 完整类名@哈希码的十六进制形式
若想打印对象各个字段的值需要重写toString()
6)equals()/hashCode
equals()用于判断两个对象内容是否一样,需要重写
根据哈希约定,如果两个对象equals()相等,则两个对象的hashCode()也应该相等,重写equals()也应重写hashCode
1.5 final关键字
final关键字可以修饰字段,方法,类,局部变量等
1) final修饰字段
final字段在定义时必须初始化,final字段不能被修改,
final一般同时与static同时使用,被称作常量
final字段一般大写
2) final修饰方法
子类中不能定义相同签名的方法
final方法不能被子类覆盖(重写)
3) final修饰类
final类不能被继承
System/String
4) final修饰局部变量
1.6 抽象类
1.6.1抽象方法
某个类的操作在不同的子类,有不同的实现方法,这个操作就是抽象方法。某个类中的操作方法无法具体实现可以定义为抽象方法。
定义格式:
[方法修饰符] abstract 返回值类型 方法名(参数列表);
注:抽象方法只有方法的声明,没有方法体
1.6.2抽象类
含有抽象方法的类必须定义为抽象类
抽象类是使用abstract 修饰的类,抽象类中不一定含有抽象方法
抽象类是Java中的引用数据类型,Java引用数据类型:类,接口,数组,枚举
抽象类可以定义变量但不可以实例化对象
package com.bjpowernode.demo02; /** * 平面图形类 * 有求面积,求求周长的操作,没法实现, 把这两个操作定义为抽象方法 * * 含有抽象方法的类必须定义为抽象类 * @author Administrator * */ public abstract class Graphics { //求面积 public abstract double getArea(); //求周长 public abstract double getPerimeter(); }
package com.bjpowernode.demo02; public class Circle extends Graphics {//圆继承父类图形 double r; @Override public double getArea() { return Math.PI * r * r; } @Override public double getPerimeter() { return 2 * Math.PI * r; } }
package com.bjpowernode.demo02; /** * 定义矩形类,继承平面图形类 * * 子类继承了抽象类, 需要重写抽象类中所有的抽象方法 * @author Administrator * */ public class Rectangle extends Graphics{ int width; int height; @Override public double getArea() { return width * height; } @Override public double getPerimeter() { return 2*(width+height); } }
package com.bjpowernode.demo02; /** * 子类继承抽象类, 如果没有重写所有的抽象方法,子类也需要定义为抽象类 * @author Administrator * */ public abstract class Triangle extends Graphics{ int a; int b; int c; @Override public double getPerimeter() { return a+b+c; } }
package com.bjpowernode.demo02; /** * * @author Administrator * */ public class Test { public static void main(String[] args) { Rectangle rect1 = new Rectangle(); rect1.width = 10; rect1.height = 5; printArea(rect1); Circle circle = new Circle(); circle.r = 10; printArea(circle); } //定义一个方法,打印任何图形的面积和周长 public static void printArea( Graphics g) { System.out.println("图形面积:" + g.getArea() ); System.out.println("图形周长:" + g.getPerimeter() ); } }
1.7 接口
1.7.1接口概述
可以简单理解为实现一个功能的封装,即一个类要扩展某个功能可通过接口实现
在Java中接口也可理解为一个协议,通过定义一组规范,各个类都可以实现这个接口,都遵守接口中的规范。
如何定义接口:
[修饰符] interface 接口名{
public abstract 方法
public static final 常量
public default 方法
}
public interface Usbable{
void connect();
//接口中的方法默认使用 public abstract修饰
}
/*定义一个游泳接口*/
interface Dao{//接口的方法全部是非静态的方法
public void add();
public void delete();
}
如何使用接口
class 类名 implements 接口名{
实现类需要重写接口中的抽象方法
}
//接口的实现类 class UserDao implements Dao{ public void add(){ System.out.println("添加员工成功"); } public void delete(){ System.out.println("删除员工成功"); } }
1) 一个类在继承父类的同时,可以实现接口
class Pencil extends Pen implements Erasable{
public void erase(){
System.out.println(“带橡皮的铅笔可以擦除”);
}
}
2) 一个类可以实现多个接口,需要重写所有接口的抽象方法:
Class Superman implments Flyable, Workable{}
3) 接口支持多继承
interface xxxxx extends Flyable, Workable{}
4) 接口可以实现多态,接口存在的意义就是多态。接口引用 只能赋值实现类对象,接口引用调用抽象方法,实际上执行的是实现类对象的方法
//测试接口 class Test{ public static void main(String[] args){ //实现关系下的多态 Dao u = new UserDao();//接口的引用类型变量指向了接口实现类的对象 u.add(); u.delete(); } }
//一个类实现了接口,没有重写接口所有的抽象方法,实现类需要使用abstract修饰为抽象类
abstract class Bird implements Flyable{}
//接口的引用赋值实现类对象
Flyable flyable = new RedBird();
//通过接口引用调用接口中的抽象方法,实际上执行的是 实现类对象的方法, 多态
flyable.fly();
1.7.2 接口内容
package com.bjpowernode.demo11;
/**
* 接口内容
* 在开发新项目时,主要使用抽象方法和常量,基本不用静态方法和default方法
*
* static静态方法和default方法主要用于对原有项目的升级, 当接口需要扩展新功能时,可以定义静态方法或default方法
*
* @author Administrator
*
*/
public interface InterfaceXXXXX {
//1) 接口中的方法默认使用public abstract修饰
void m1(); //实现类需要重写该方法, 否则实现类需要定义为抽象类
//2) 在接口中可以定义常量, 接口中的字段默认使用public static final 修饰
int XX = 10;
//3)在接口中可以定义静态方法
public static void m2() {
System.out.println("接口中的静态方法");
}
//4) 在接口中的方法使用default修饰 ,可以有默认的方法体
public default void m3() {
System.out.println("default方法,可以有默认的方法体, 实现类可以重写该 方法,也可以不重写");
}
}
1.7.3 接口和抽象类的异同
相同点:
1)都可以定义抽象方法
2)都不能实例化对象
3)抽象类的子类需要重写抽象类的抽象方法,接口的实现类需要重写接口的抽象方法
4)都可以定义public static 方法,都可以定义 public static final常量
不同点:
1) 意义不同
抽象类一般表示其他类的父类
接口是功能的封装
2) 定义方式
抽象类使用 abstract class
接口使用 interface定义
3) 内容不同
抽象类除了抽象方法以外,普通类的所有成员都可以定义,包括构造方法
在(JDK8)中,除了抽象方法外,还可以定义常量,default方法和静态方法
4) 应用场合不同
仅为扩展功能优先使用接口,接口比较灵活,一个类可以实现多个接口。
如果除了功能外,还需要保存数据,需要使用抽象类,抽象类表示类与 类之间的层次关系,同时约束所有子类都具有某个功能。
1.7.4 接口在开发中应用
1)某种程度上可以解决类的多继承问题
Java中的类只支持单继承
如描述打工的学生
2)接口可以看作是一个规范
可以在接口定义的一套操作规范,相关的业务逻辑模块都要遵循这个规范,即都要实现这个接口
3)通过接口可以实现代码的可插拔,更灵活,代码具有可扩展性
4)通过接口可以使项目分层
如:
业务逻辑操作数据库
1.8 类之间的关系
继承,实现(接口),依赖,关联,聚合,组合
继承
也称泛化关系,子类继承父类,子接口继承父接口
实现
一个类实现了一个接口
依赖
如果A中的某个方法,方法的参数/方法的返回值/局部变量使用B类定义的,称A类依赖B类
关联
如果A类使用B类定义了成员变量,称A类关联B类
聚合
聚合是关联的一种,一个A类由若干B类组成,但A类不能决定B类的生命周期
组合
组合是关联的一种,如果A类包括若干B类,A类可以决定B类的生命周期
父类, 父类是通用类,一般类,子类是特殊类, 也只能当子类与父类符合is a关系时才可以使用继承.
like a, 实现类 like a 接口, 一种实现关系
has a , 关联关系 ,
1.9 内部类
可以在一个类A的内部定义另外一个类B, 类B就是内部类, 对应的类A称为外部类
内部类一般只为外部为服务
内部类分类: 成员内部类, 静态内部类, 局部内部类, 匿名内部类
1.9.1 成员内部类
class Outer{
class Inner{ //成员内部类
}
}
1) 成员内部类就像实例变量,实例方法一样,是属于某个外部类对象的
2) 成员内部类编译生成独立的字节码文件: 外部类名$内部类名.class
3) 一般情况下, 是在外部类的实例方法中,通过成员内部类创建对象
也可以在外部类的外面使用成员内部类, 成员内部类是依附于某个外部类对象
4) 成员内部类中也可以定义实例变量/实例方法/构造方法, 但是不能定义静态成员
1.9.2 静态内部类
class Outer2 { static class Inner2{ //静态内部类 } }
1.9.3 局部内部类
class Outer3{ public void m1(){ int xx = 10 ; //局部变量 class Inner3{ //局部内部类 } //局部内部类只能在定义之后 , 与包含它的大括弧之间使用 } }
1.9.4 匿名内部类
抽象类的引用可以赋值匿名内部类对象
接口引用可以赋值匿名内部类对象
常用法
某个方法的形参是一个抽象类/接口, 在调用方法时,传递匿名内部类对象
1)接口的引用需要指向一个实现类对象,若实现类只实现一次,可直接让接口指向匿名内部类对象
2) 抽象类不能实例化对象,可以指向匿名内部类对象
注意:方法的形参是一个抽象类,调用方法时,传递抽象类匿名内部类对象
abstract class Person{ public abstract void eat(); } //不使用匿名内部类实现的抽象方法 class Child extends Person{ public void eat(){ System.out.println("吃零食"); } } class Test01{ public static void main(String[] args){ Person p = new Child(); p.eat(); } } //使用匿名内部类实现的抽象方法 class Test02{ public static void main(String[] args){ Person p1 = new Person(){ public void eat(){ System.out.println("吃零食"); } }; p1.eat(); } }
2.异常
2.1概述
异常情形是指阻止当前方法或者作用域继续执行的问题。
之前遇到的异常:
空指针异常
类型转换异常
算术异常
通过异常处理,提高程序的健壮性(robust)
2.2 异常处理
2.2.1 捕获处理
try{
对可能产生异常的代码检视
这一段代码可能产生异常,也可能没有异常
如果try代码块中某一条语句产生了异常, 就立即跳转到对应的catch子句执行, try代码块后面的语句不再执行
try代码块中可能会产生多个异常,通过多个catch子句捕获
}catch( 异常类型1 e1 ){
//对异常类型1的异常进行预处理
//在开发时, 一般的 处理方式就是把异常打印到屏幕上, 方便程序员进行调试
e1.printStackTrace();
}catch( 异常类型2 e2){
//对异常类型2进行预处理
//如果多个catch子句中异常类型有继承关系 , 应该先捕获子异常,再捕获父异常
}finally{
// finally不是必须的, finally子句不管是否产生异常, 总是会执行
// 一般在finally子句中释放系统资源
}
2.2.2 抛出处理
在定义方法时, 如果方法体产生了异常, 可以在方法声明位置通过throws声明抛出
public void mmm() throws IOException{
}
try..catch捕获还是throws抛出??
1) 定义方法时,可以throws声明抛出, 提醒调用者可能会出异常, 需要有针对性的措施
2) 在调用方法时,如果方法声明了受检异常, 需要捕获处理
2.3 方法覆盖中的异常处理
子类重写的方法,可以抛出比父类方法更小的异常
如果父类方法没有抛出异常, 子类方法也不能抛出异常
如果父类方法抛出了异常, 子类方法可以抛出相同的异常
也可以抛出父类异常的子异常
也可以不抛出异常
2.4 异常在开发中的应用
1) 定义一个类继承Exception
2) 一般提供无参构造 与 String参数的构造
3) 在需要的位置, 通过throw抛出一个异常对象
4) 所在的方法通过throws 声明一个异常
5) 调用方法时,捕获处理异常
3. 数组
3.1定义
什么是数组
数组是一个简单的复合数据类型,它是一系列有序数据的集合,它当中的每一个数据都具有相同的数据类型,我们通过数组名加上一个不会越界下标值来唯一确定数组中的元素。
数据类型 [] 数组名 = new 数据类型[长度]
1) 数据类型就是数组中存储元素的类型
2) [] 表示它是一个数组
3) 数组名本质上就是一个变量名,
4) new运算符会在堆中分配 一块新的存储空间, 把这块存储空间的起始地址保存到数组名中
5) 这块存储空间的大小是 数据类型的大小 * 数组的长度
如:
int [] data = new int[5];
1) data是数组名, 其实就是一个变量名, 它的数据类型是: int []
2) new在堆中分配 一块连续的存储空间, 这块存储空间可以存储 5 个int类型数据
有时数组的定义也可以写成这样:
数据类型 数组名[] = new 数据类型[长度];
如:
double scores[] = new double[100];
3.2数组元素的访问
数组通过索引值(下标)访问数组的每个元素
定义了数组之后,系统给每个元素指定一个索引值, 索引值是从0开始的
如:
data[0] = 10;
data[1] = 10;
data[2] = 10;
data[3] = 10;
data[4] = 10;
data[5] = 220; //数组的最大下标是4, 运行时出现数组下标越界的异常
为什么通过索引值就能访问到数组的元素??
3.3静态初始化
先定义数组 ,再给数组元素赋值, 数组的动态初始化
在定义数组的同时可以给数组元素赋值, 数组的静态初始化
定义了数组 ,如果没有给数组元素赋值, 数组会进行默认初始化
3.4数组的遍历
for循环遍历
foreach遍历
3.5数组作为对象方法参数
3.5.1数组作为方法参数
在调用方法时, 把实参数组传递给形参数组, 现在形参数组与实参数组指向了堆中同一个数组
3.5.2 修改形参数组的元素值
在方法体中, 修改形参数组的元素,实际上就是修改实参数组的元素
3.5.3 给形参数组重新赋值
在方法体中, 对形参数组进行了重新赋值, 形参数组指向了一个新的数组 , 不再指向实参 数组
3.5.4 数组作为方法的返回值类型
如果在方法体中想返回一个新的数组, 方法 的返回值类型可以是一个数组类型
3.5.5main方法的参数
3.6数组特点
优点:
数组可以通过索引值快速的访问到每个元素
缺点:
在数组中插入元素,删除元素时效率低, 需要数组扩容, 元素的复制
3.7数组扩容
定义数组时,需要指定数组的长度, 数组存储元素的个数就确定了, 如果还想存储更多的数据, 需要对数组进行扩容
1) 定义一个更大的数组
2) 把原来数组的内容复制到新数组中
3) 让原来的数组名指向新的数组
3.8二维数组
二维数组的每个元素又是一个一维数组
数据类型[][] 数组名 = new 类型[长度][];
3.9对象数组
数组的元素是对象
数组元素的类型是引用类型
数组元素存储的是对象的引用
3.10Arrays工具类
java.util包中的Arrays工具类,提供了若干操作数组的方法
|
3.11排序算法
选择排序,冒泡排序
3.12查找算法
二分查找
折半查找
前提是数组由小到大排序