目录
1、final关键字
final可以修饰类、方法和变量
1)修饰类时,该类不可以被别的类继承,但是可以继承别的类
2)修饰方法时,该方法不能被子类重写
3)修饰变量时,变量只能被赋值一次
2、接口
接口用interface关键字修饰:
public interface Inter{
}
类和接口之间是实现关系,用implements修饰
public class Cat implements Inter{
}
接口中有且只能有常量或者抽象方法, 原因是因为:
•成员变量有默认修饰符: public static final
•成员方法有默认修饰符: public abstract
注意: JDK1.8的时候, 接口中加入了两个新的成员: 静态方法, 默认方法(必须用default修饰).
3、权限修饰符
1.访问权限修饰符的权限从大到小分别是:
public > protected > 默认 > private
2.在实际开发中, 如果没有特殊需求, 则成员变量都用private修饰, 其它都用public修饰.
3.总结四个访问权限修饰符的作用:
1.private: 强调的是给自己使用.
2.默认: 强调的是给同包下的类使用.
3.protected: 强调的是给子类使用.
4.public: 强调的是给大家使用.
4、Scanner对象使用nextInt接收整数之后无法使用nextLine接收字符串
原因:
nextInt输入的是"数字\r\n",只接收了数字部分,\r\n没有接收,nextLine的结束标志是"\r\n",因此直接结束
解决方法:
1、nextLine接收之前调用一次nextLine
2、重新new Scanner对象
3、使用字符串接收数字,再转化为整数(常用)
Scanner sc = new Scanner();
String sNum = sc.nextLine();
int num = Integer.parseInt();
5、Java的常量优化机制
1、针对byte类型
如果是常量相加: 看运算的结果在不在左边的数据类型范围内,不在则报错
如果是变量相加: 先提升类型,再运算。提升规则:
byte\char\short -> int -> long -> float -> double
2、针对String类型
如果是常量拼接: 直接拼接,不(在堆区)开辟新的空间
如果是变量拼接: 会在堆区开辟新空间
6、包装类
解释: 为了对基本类型进行更多更方便的操作, Java就针对每一种基本类型提供了一个对应的引用类型, 这就是包装类.
基本类型 对应的包装类
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double
boolean Boolean
public class IntegerDemo {
public static void main(String[] args) {
//1、调用Integer的两种构造方法
Integer i1 = new Integer(100);
Integer i2 = new Integer("200");
//2、int和String的相互转换
//2.1 把int 转换成 String
int i3 = 10;
//方法1
String s1 = i3 + "";//常用
//方法2
String s2 = String.valueOf(i3);
//2.1 把String 转换成 int
String s3 = "100";
//方法1
int i4 = Integer.parseInt(s3);//常用
int i5 = new Integer(s3).intValue();
}
}
7、Date与SimpleDateFormat类
获取当前毫秒值并转化为指定格式
1、Date类常用方法:getTime() 获取当前毫秒值
2、SimpleDateFormat类常用方法:
•public final String format(Date date)
解释: 用来格式化日期的.
•public Date parse(String source)
解释: 用来解析字符串形式的日期的.
Date d = new Date();
SimpleDateFormat sd = new SimpleDateFormat("yyyy年M月d日 H:m:s:S");
System.out.println(sd.format(d));
8、Calendar类用法
public class Demo1 {
public static void main(String[] args) {
/*
*需求
1.提示用户录入年份.
2.计算该年的2月有多少天, 并将结果打印到控制台上.
* */
//1、提示用户输入年份
System.out.println("请输入年份:");
Scanner sc = new Scanner(System.in);
int year = sc.nextInt();
//2、设置当前日历时间为输入年份的3月1日
Calendar c = Calendar.getInstance();
c.set(year,2,1);
//3、把当前时间往前推一天
c.add(Calendar.DAY_OF_MONTH,-1);
//4、获取当前日期为月中的第几天
int ret = c.get(Calendar.DAY_OF_MONTH);
System.out.println(DateUtils.date2String(c.getTime()));
//5、输出结果
System.out.println(year+"年的2月有"+ret+"天");
}
}
9、内部类
1、定义
内部类分为两种:成员内部类和局部内部类,其中:
成员内部类: 定义在成员位置的内部类,一般多用于框架
局部内部类: 定义在方法中的内部类
2、关于内部类,我们用的最多的是匿名内部类,属于局部内部类的一种
3、匿名内部类:
定义: 没有名字的局部内部类
前提: 必须有一个类(抽象类, 普通类均可), 或者接口
格式:
new 类名或者接口名() {
//重写类或者接口中所有的抽象方法
};
本质: 匿名内部类是一个继承了类或者实现了接口的匿名的子类对象
使用场景:
1.当对对象方法(即: 成员方法)仅调用一次的时候.
2.匿名内部类可以作为方法的实参进行传递.
3.当接口或者抽象类中的抽象方法在3个(含)以下时, 就可以考虑使用匿名内部类的形式来创建对象
public class InnerClass {
public static void main(String[] args) {
//1、抽象类
new Animal(){
@Override
public void eat(){
System.out.println("人是铁,饭是钢");
}
}.eat();
//2、接口
new Jumpping(){
@Override
public void jump() {
System.out.println("跳高运动");
}
}.jump();
//3、匿名内部类当做方法的参数
show(new Animal() {
@Override
public void eat() {
System.out.println("饿了就要吃饭");
}
});
}
public static void show(Animal an){
an.eat();
}
}
10、集合
集合是用来存储多个同类型数据的容器, 它的长度是可以变化的.
1.集合的顶层都是接口, 其中Collection接口是单列集合的顶层接口, Map接口是双列集合的顶层接口.
2.Collection接口(单列集合)有两大子体系:
–List体系的特点是: 有序, 可重复.
–Set体系的特点是: 无序, 唯一.
10.1 Collection集合
因为Collection是接口, 所以不能直接通过new关键字来创建它的对象。通过多态的方式, 创建其子类对象, 从而实现创建Collection接口对象.
Collection<String> list = new ArrayList<String>();
解释:
1.集合后边的<数据类型>是泛型的意思, 泛型是用来限定集合中存储元素的数据类型的.
2.例如:
–Collection说明集合中只能存储字符串.
–Collection说明集合中只能存储整数.
3.泛型只能是引用数据类型, 且在实际开发中, 泛型一般只结合集合来一起使用.
常用方法:
•public boolean add(E e) 添加元素.
•public boolean remove(Object obj) 从集合中移除指定的元素.
•public void clear() 清空集合对象
•public boolean contains(Object obj) 判断集合中是否包含指定的元素
•public boolean isEmpty() 判断集合是否为空
public int size() 获取集合的长度, 即集合中元素的个数
10.2 集合遍历Iterator
public class IteratorDemo {
public static void main(String[] args) {
Collection<String> c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Iterator<String> i = c.iterator();
while (i.hasNext()){
System.out.println(i.next());
}
}
}
10.3 List集合
List集合的元素特点是: 有序, 可重复, 元素有索引.
ListIterator接口, 是List集合特有的迭代器.
列表迭代器常用方法:
hasNext()
next()
hasPrevios()
previos()
10.4 并发修改异常
问题: 当使用普通迭代器(Iterator)遍历List集合的同时, 又往集合中添加元素, 就会报并发修改异常.
解决方法:
1、通过列表迭代器ListIterator解决
注意: 需要用ListIterator#add方法,新增的对象是在迭代器当前位置
2、通过size()、get()方法解决
注意: 新增的对象集合最后
public class Demo1 {
public static void main(String[] args) {
List<String> lst = new ArrayList<>();
lst.add("Hello");
lst.add("World");
lst.add("Java");
//1、方法1,使用Iterator,报并发修改异常
/*Iterator it = lst.iterator();
while(it.hasNext()){
if("World".equals(it.next())){
lst.add("Best");//报并发修改异常
}
}*/
//2、方法2,使用ListIterator
/*ListIterator<String> lit = lst.listIterator();
while(lit.hasNext()){
if("World".equals(lit.next())){
lit.add("Best");//在集合当前位置新增([Hello, World, Heima, Java])
}
}*/
//3、方法3,使用size()和get()
for(int i = 0; i < lst.size(); i ++){
if("World".equals(lst.get(i))){
lst.add("Best");//在集合最后的位置新增([Hello, World, Java, Heima])
}
}
System.out.println(lst);
}
}
10.5 Map集合
概述: Map集合是双列集合的顶层接口, 它是用来存储键值对对象的, 其中键具有唯一性, 而值是可以重复的.
格式: public interface Map<K, V> //K: 键的类型, V: 值的类型.
常用方法:
方法名 说明
V put(K key,V value) 添加元素
V remove(Object key) 根据键删除键值对元素
void clear() 移除所有的键值对元素
boolean containsKey(Object key) 判断集合是否包含指定的键
boolean containsValue(Object value) 判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中键值对的个数
V get(Object key) 根据键获取值
Set keySet() 获取所有键的集合
Collection values() 获取所有值的集合
Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合
public static void main(String[] args) {
HashMap<String,String> hm = new HashMap<>();
hm.put("乔峰","阿朱");
hm.put("段誉","王语嫣");
hm.put("杨过","小龙女");
Set<String> keys = hm.keySet();
//方法1
/*for(String key:keys){
System.out.println(key+":"+hm.get(key));
}*/
//方法2
/*Iterator<String> it = keys.iterator();
while(it.hasNext()){
String key = it.next();
System.out.println(key+":"+hm.get(key));
}*/
//方法3
Set<Map.Entry<String, String>> entries = hm.entrySet();
Iterator<Map.Entry<String, String>> it = entries.iterator();
while (it.hasNext()) {
Map.Entry<String, String> mp = it.next();
System.out.println(mp.getKey() + ":" + mp.getValue());
}
}
10.6 Collections工具类
Collections类是针对集合操作的工具类.
常用方法:
方法名 说明
public static void sort(List list) 将指定的列表按升序排序
public static void reverse(List<?> list) 反转指定列表中元素的顺序
public static void shuffle(List<?> list) 使用默认的随机源随机排列指定的列表
11、可变参数
格式:
修饰符 返回值类型 方法名(数据类型… 变量名) { }
注意:
1.这里的变量其实是一个数组.
2.如果一个方法有多个参数,其中包含可变参数,可变参数要放在最后.
12、Lambda表达式
格式: (形式参数) -> {代码块}
前提: 有一个接口, 且接口中有且仅有一个抽象方法
实例:
public class LambdaDemo {
public static void main(String[] args){
//方式1 匿名内部类
show(new Animal(){
@Override
public void eat(){
System.out.println("动物要吃饭!");
}
});
//方式2 Lambda表达式
show(()->{
System.out.print("动物要吃饭");
});
}
public static void show(Animal an){
an.eat();
}
}
省略规则:
•参数类型可以省略。但是有多个参数的情况下,不能只省略一个
•如果参数有且仅有一个,那么小括号可以省略
•如果代码块的语句只有一条,可以省略大括号和分号,和return关键字
Lambda表达式和匿名内部类的区别:
•所需类型不同
–匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
–Lambda表达式:只能是接口
•使用限制不同
–如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
–如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
•实现原理不同
–匿名内部类:编译之后,产生一个单独的.class字节码文件
–Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
13、异常
Java中的异常体系如下:
Throwable //异常体系的最顶层类
Error //表示错误
Exception //这个才是我们说应的
非RunTimeExceptionException
RuntimeException
try.catch.finally:
格式:
try{
//可能出问题的代码
System.exit(0);//代码结束,finally中的代码不会执行
} catch(Exception e) {
e.printStackTrace()
return;//代码结束之前finally中的代码会执行
}finally{
//正常情况下这里的代码都会执行,一般用来释放资源
//这里的代码不受return影响
//这里的代码受exit影响
}
14、File类
14.1 构造方法
File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
示例:
public class FileDemo {
public static void main(String[] args) {
File f1 = new File("d:/abc/1.txt");
System.out.println("f1:"+f1);
File f2 = new File("d:\\abc\\1.txt");
System.out.println("f2:"+f2);
File f3 = new File("d:\\abc\\","1.txt");
System.out.println("f3:"+f3);
File f4 = new File(new File("d:/abc"),"1.txt");
System.out.println("f4:"+f4);
}
}
输出:
f1:d:\abc\1.txt
f2:d:\abc\1.txt
f3:d:\abc\1.txt
f4:d:\abc\1.txt
14.2 文件创建方法
public boolean createNewFile() 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir() 创建由此抽象路径名命名的目录
public boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
14.3 判断和获取功能
//判断方法:
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
//获取方法
public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径名字符串
public String getName() 返回由此抽象路径名表示的文件或目录的名称
public String[] list() 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles() 返回此抽象路径名表示的目录中的文件和目录的File对象数组
15、IO流
15.1 分类
四种IO流:
–字节输入流
解释: 以字节为单位, 来读取数据. 顶层抽象类是: InputStream.
–字节输出流
解释: 以字节为单位, 来写入数据. 顶层抽象类是: OutputStream.
–字符输入流
解释: 以字符为单位, 来读取数据. 顶层抽象类是: Reader.
–字符输出流
解释: 以字符为单位, 来写入数据. 顶层抽象类是: Writer.
15.3 字节流
1、FileOutputStream //普通字节输出流
构造方法:
•public FileOutputStream(String name)
•public FileOutputStream(File file)
•public FileOutputStream(String name, boolean append)
•public FileOutputStream(File file, boolean append)
//当append的值为true时, 表示往文件中追加数据
2、FileInputStream //普通字节输入流
3、BufferedOutputStream //高效字节输出流
4、BufferedInputStream //高效字节输入流
15.5 字符集
–ASCII字符集:American Stanford Code For Information Interchange: 美国信息交换标准代码.
是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
–ISO-8859-1: 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII.
–GBXXX字符集:
•GB2312: 中文码表, 兼容ASCII. 包含7000多个简体汉字.
•GBK:最常用的中文码表. 是GB2312码表的升级版, 融合了更多的中文文字符号, 兼容ASCII.
解释: GBK码表共收录了21003个汉字.
•GB18030: 最新的中文码表, 收录汉字70244个.
–Unicode字符集:
•为表达任意语言的任意字符而设计, 是业界的一种标准, 也称为统一码, 标准万国码. 它最多使用4个字节的数字来表达每个字母, 符号或者文字. 有3种编码方案, 分别是: UTF-8, UTF-16, UTF-32.
•UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用1~4个字节为每个字符编码.
–编码规则:
•128个US-ASCII字符,只需一个字节编码
•拉丁文等字符,需要二个字节编码
•大部分常用字(含中文),使用三个字节编码
•其他极少使用的Unicode辅助字符,使用四字节编码
public static void main(String[] args) {
try {
System.out.println(new String("中国".getBytes("gbk")));
System.out.println(Arrays.toString("中国".getBytes("gbk")));
System.out.println(new String("中国".getBytes("UTF-8")));
System.out.println(Arrays.toString("中国".getBytes("UTF-8")));
System.out.println(new String("中国".getBytes("ISO-8859-1")));
System.out.println(Arrays.toString("中国".getBytes("ISO-8859-1")));System.out.println(new String("中国".getBytes("ISO-8859-1")));
System.out.println(new String("中国".getBytes("ASCII")));
System.out.println(Arrays.toString("中国".getBytes("ASCII")));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
15.5 字符流
1、FileWriter
2、FileReader
3、BufferedWriter
4、BufferedReader//一次读一行,必须掌握
15.6 try.with.resource
public static void main(String[] args) {
try(
FileOutputStream fos = new FileOutputStream("d:/Atest/2.txt");
)//jdk1.7之后的新特性,写在()中的对象必须实现AutoCloseable接口并重写close方法
{
fos.write("这是jdk1.7之后的特性!\r\n".getBytes());
} //大括号之后自动完成资源回收
catch(Exception e){
e.printStackTrace();
}
}
15.7 序列化流
1、对象序列化
–对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
•注意事项
–一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口
–Serializable是一个标记接口,实现该接口,不需要重写任何方法
对象序列化流: ObjectOutputStream
将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。
ObjectOutputStream(OutputStream out)
void writeObject(Object obj)
2、对象反序列化:
ObjectInputStream
ObjectInputStream(InputStream in)
Object readObject()
3、serialVersionUID&transient
问题1、当我们序列化了一个对象之后,如果修改了对应的JavaBean,再进行反序列化,会不会出问题
问题2、如果出问题了怎么解决
问题3、如果类中的某个属性不想被序列化,如何操作
•serialVersionUID
–用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
•会出问题,会抛出InvalidClassException异常
–如果出问题了,如何解决呢?
•给对象所属的类加一个serialVersionUID
–private static final long serialVersionUID = 1L;
•transient
–如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
15.8 第三方jar包的使用方法
1、在项目下新建lib文件下
2、把第三方jar包放到lib文件下
3、配置运行环境。即把jar包加载到当前项目(选中jar包,右键点击add as library)
16、多线程
16.1 两种实现多线程方式
方式一: 继承Tread类
自定义线程类:
public class MyThread extends Thread {
//定义指定线程名称的构造方法
public MyThread(String name) {
//调用父类的String参数的构造方法,指定线程的名称
super(name);
}
/**
* 重写run方法,完成该线程执行的逻辑
*/
@Override
public void run() {
//业务业务代码
}
}
public class Demo01 {
public static void main(String[] args) {
//创建自定义线程对象
MyThread mt = new MyThread("新的线程!");
//开启新线程
mt.start();
}
}
方式二: 实现java.lang.Runnable接口
public class MyRunnable implements Runnable{
@Override
public void run() {
//业务代码
}
}
public class Demo {
public static void main(String[] args) {
//创建自定义类对象 线程任务对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t = new Thread(mr, "新县城");
t.start();
}
}
或者通过匿名内部类
public class InnerClassTreadDemo {
public static void main(String[] args) {
//方式1,匿名内部类,Thread
new Thread(){
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("Thread匿名内部类..."+i);
}
}
}.start();
//方式2,匿名内部类Runnable接口
new Thread(new Runnable(){
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("Runnable匿名内部类..."+i);
}
}
}).start();
//方式3,Runnable的Lambda表达是
//Lambda表达式的方式没有显示的重写run方法,导致JVM有时找不到对应的run方法
//可能会把其当作普通的方法执行。不建议用Lambda表达式的方法
new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println("Runnable的Lambda方式..."+i);
}
}).start();
}
}
16.2 线程安全
Java中提供同步机制(synchronized)来解决线程同步问题
有三种方式完成同步操作:
1.同步代码块。
2.同步方法。
3.锁机制。
•同步代码块: synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
格式:
synchronized(同步锁){
需要同步操作的代码
}
锁对象 可以是任意类型。
static Object lock = new Object();//小技巧,同步锁可以使用类自身的字节码文件: 类名.class。而不用重新new对象
•同步方法: 使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。
public synchronized void method(){
可能会产生线程安全问题的代码
}
锁机制:
JDK5以后提供了一个新的锁对象Lock
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock() 创建一个ReentrantLock的实例
void lock() 获得锁
void unlock() 释放锁
程序示例:
public class SellTicket extends Thread{
private static int tickets = 30;//票的总数
private static Lock lock = new ReentrantLock();
public SellTicket(String name) {
super(name);
}
@Override
public void run(){
while(true){
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
if(tickets > 0){
String name = Thread.currentThread().getName();
System.out.println(name+"售出第"+(tickets--)+"号票");
}
else{
lock.unlock();
break;
}
lock.unlock();
}
}
}
public class ThreadLockDemo {
public static void main(String[] args) {
new SellTicket("窗口1").start();
new SellTicket("窗口2").start();
new SellTicket("窗口3").start();
}
}
16.3 优先级
多线程的默认优先级是5,优先级范围是1~10。数字越大,优先级越高。
final int getPriority() 返回此线程的优先级
final void setPriority(int newPriority) 更改此线程的优先级, 线程默认优先级是5;线程优先级的范围是:1-10
16.4 线程池
实现方式一:
JDK提供的线程池并不是直接创建对象,而是用工厂类创建线程池对象。
•线程池工厂类:Executors
–public static ExecutorService newFixedThreadPool(int nThreads)
方法解释: 线程池工厂类创建固定线程数的方法
•线程池接口:ExecutorService
–public Future<?> submit(Runnable task)
方法解释: 使用线程池对象方法submit提交线程执行任务,这是实现多线程的第三种方式
–public void shutdown()
方法解释: 关闭线程池
实现方式二:
JDK5以后, 实现多线程有了一种新的方式, 即: 通过Callable接口实现.
优点:
•线程执行后, 可以具有返回值.
•可以抛出异常.
局限:
•该方式只能结合线程池一起使用.
API:
•线程池工厂类:Executors
–public static ExecutorService newFixedThreadPool(int nThreads)
方法解释: 线程池工厂类创建固定线程数的方法
–public static ExecutorService newCachedThreadPool()
方法解释: 创建一个可根据需要创建新线程的线程池
•线程池接口:ExecutorService
–public Future<?> submit(Runnable task)
方法解释: 使用线程池对象方法submit提交线程执行任务,这是实现多线程的第三种方式
–public Future submit(Callable task)
方法解释: 使用线程池对象方法submit提交线程执行任务,这是实现多线程的第三种方式
–public void shutdown()
方法解释: 关闭线程池
示例:
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
for(int i = 0; i < 50; i ++){
System.out.println("实现Callable的线程............");
}
return "实现Callable的线程的返回值";
}
}
public class CallableDemo {
public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(5);
Future future = e.submit(new MyCallable());
System.out.println(future.get());
}
}
17 网络编程
17.1 InetAddress
InetAddress:此类表示Internet协议(IP)地址
方法名 说明
static InetAddress getByName(String host) 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
String getHostName() 获取此IP地址的主机名
String getHostAddress() 返回文本显示中的IP地址字符串
示例:
public class InetAddressDemo {
public static void main(String[] args) {
InetAddress iAddr = null;
try {
//iAddr = InetAddress.getByName("192.68.1.121");
iAddr = InetAddress.getByName("myComputerName");
} catch (UnknownHostException e) {
e.printStackTrace();
}
String hostAddr = iAddr.getHostAddress();
String hostName = iAddr.getHostName();
System.out.println("inetAddr:"+iAddr);
System.out.println("hostAddr:"+hostAddr);
System.out.println("hostName:"+hostName);
}
}
17.2 UDP和TCP协议
对比:
序号;UDP;TCP
1、面向无连接;面向有连接
2、采用数据包发送数据,单包数据不能超过64k;采用IO流的形式放数据,理论上数据大小无限制
3、不可靠;可靠
4、效率比较高;效率比较低
5、不区分客户端和服务端;区分客户端和服务端
UDP类: DatagramSocket类
方法名 说明
DatagramSocket() 创建数据报套接字并将其绑定到本机地址上的任何可用端口
DatagramPacket(byte[] buf,int len,InetAddress add,int port) 创建数据包,发送长度为len的数据包到指定主机的指定端口
void send(DatagramPacket p) 发送数据报包
void close() 关闭数据报套接字
void receive(DatagramPacket p) 从此套接字接受数据报包
UDP收发示例:
public class UDPDemo {
public static void main(String[] args) {
DatagramSocket ds = null;
InetAddress iAddr = null;
{
try {
//1、创建Socket对象
ds = new DatagramSocket(9090);
//2、创建地址对象
iAddr = InetAddress.getByName("127.0.0.1");
} catch (Exception e) {
e.printStackTrace();
}
}
//3、创建发送包对象
byte[] buf = new byte[1024];
String revStr = null;
DatagramPacket dp = new DatagramPacket(buf,1024,iAddr,9527);
try {
//4、发送数据
dp.setData("世界你好,我是UDP发送者".getBytes("gbk"));
ds.send(dp);
//5、接收数据
do{
ds.receive(dp);
revStr = new String(dp.getData(),0,dp.getLength(),"gbk");
System.out.println(revStr);
}while(!"exit".equals(revStr));
} catch (Exception e) {
e.printStackTrace();
}
//6、关闭Socket
ds.close();
}
}
TCP类:
–Java为客户端提供了Socket类,为服务器端提供了ServerSocket类
客户端之Socket类:
方法名 说明
Socket(InetAddress address,int port) 创建流套接字并将其连接到指定IP指定端口号
Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号
InputStream getInputStream() 返回此套接字的输入流
OutputStream getOutputStream() 返回此套接字的输出流
客户端示例:
public class Client {
public static void main(String[] args) throws Exception {
byte[] bs = new byte[1024];
Socket client =new Socket("127.0.0.1",30001);
OutputStream os = client.getOutputStream();
InputStream is = client.getInputStream();
os.write("你好,世界!".getBytes("gbk"));
is.read(bs);
System.out.println(new String(bs,0,bs.length,"gbk"));
os.close();
}
}
服务端之ServerSocket类:
ServletSocket(int port) 创建绑定到指定端口的服务器套接字
Socket accept() 监听要连接到此的套接字并接受它
示例程序:
public class Server {
public static void main(String[] args) throws Exception {
byte[] bs = new byte[1024];
ServerSocket server = new ServerSocket(30001);
Socket client = server.accept();
InputStream is = client.getInputStream();
is.read(bs);
System.out.println(new String(bs,0,bs.length,"gbk"));
OutputStream os = client.getOutputStream();
os.write("你好,客户端!".getBytes("gbk"));
client.close();
server.close();
}
}
注意:shutdownOutput :发送完数据之后,告诉对方发送已完成。当接收方使用while循环接收数据时,只有在发送方关闭发送通道或使用shutdownOutput方法,才会给接收方一个发送结束标志(null或者-1),否者接收方会一直等待。
18、Junit
Junit介绍:
Junit是一个Java语言的单元测试框架,属于白盒测试,简单理解为可以用于取代java的main方法。Junit属于第三方工具,需要导入jar包后使用。
Junit下载
提取码:jdpq
Junit使用:
1.编写测试类,简单理解Junit可以用于取代java的main方法
2.在测试类方法上添加注解 @Test
3.@Test修饰的方法要求:public void 方法名() {…} ,方法名自定义建议test开头,没有参数。
4.添加Junit库到lib文件夹中,然后进行jar包关联
常用注解:
•@Test,用于修饰需要执行的测试方法
•@Before,修饰的方法会在测试方法之前被自动执行
•@After,修饰的方法会在测试方法执行之后自动被执行
public class JunitDemo {
@Before
public void testShow(){
System.out.println("一般用来初始化对象,或者加载驱动");
}
@Test
public void testShow1(){
System.out.println("this is show1");
}
@After
public void testShow4(){
System.out.println("一般用来释放资源");
}
}
19、反射
19.1 反射介绍
反射是指,在程序运行期间,通过过去类的字节码文件对象,来使用类的成员(成员变量、构造方法、成员方法)的一种技术。
19.2 获取字节码文件对象
•方法一:类名.class属性 //一般用于互斥锁
•方法二:对象名.getClass()方法 //一般用于比较两个对象是否同类
•方法三:Class.forName(全类名)方法 //一般用于反射
19.3 反射获取构造方法并创建对象
Class类获取构造方法对象
方法名 说明
Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组
Constructor getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象
Constructor getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造方法对象
Constructor类创建对象
方法名 说明
T newInstance(Object...initargs) 根据指定的构造方法创建对象
示例:
public class ConstructorDemo {
public static void main(String[] args) throws Exception {
//获取字节码文件对象
Class clas = Class.forName("com.study.reflect.Pojo.Student");
clas.newInstance();
//方法1,获取无参构造方法
Constructor con = clas.getConstructor();
//方法1,创建对象
Student o = (com.study.reflect.Pojo.Student)con.newInstance();
o.study();
//方法2,获取有参构造方法
Constructor con1 = clas.getConstructor(String.class,int.class,String.class);
//方法2,创建对象
Student o1 = (Student)con1.newInstance("Tom",12,"tom.study.com");
System.out.println(o1.toString());
//方法3,获取私有构造方法
Constructor con2 = clas.getDeclaredConstructor(String.class,String.class);
//暴力反射,取消权限检查
con2.setAccessible(true);//通过私有构造创建对象必须取消权限检查,否则报错
//方法3,创建对象
Student o2 = (Student)con2.newInstance("Tonny","Tonny.study.com");//报错
System.out.println(o2);
}
}
19.3 获取成员变量
Field类:
方法名 说明
Field[] getFields() 返回所有公共成员变量对象的数组
Field[] getDeclaredFields() 返回所有成员变量对象的数组
Field getField(String name) 返回单个公共成员变量对象
Field getDeclaredField(String name) 返回单个成员变量对象
Field类用于给成员赋值的方法:
方法名 说明
void set(Object obj,Object value) 给obj对象的成员变量赋值为value
示例:
public class FieldDemo {
public static void main(String[] args) throws Exception {
//1、获取字节码文件对象
Class clas = Class.forName("com.study.reflect.Pojo.Student");
//2、创建对象
Student s = (Student)clas.newInstance();
//3、获取成员变量
//3.1 获取所有的成员变量
Field[] fields = clas.getDeclaredFields();
for(Field field : fields){
System.out.println(field);
}
//3.1 获取单个成员变量
Field name = clas.getDeclaredField("name");
name.setAccessible(true);//私有成员变量,必须设置取消权限检查
//4、设置成员变量
name.set(s,"Sam");
System.out.println(s);
}
}
19.4获取成员方法
Method类:
方法名 说明
Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods() 返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>... parameterTypes) 返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象
Method类用于执行方法的方法:
方法名 说明
Object invoke(Object obj,Object... args) 调用obj对象的成员方法,参数是args,返回值是Object类型
示例:
public class MethodDemo {
public static void main(String[] args) throws Exception {
//1、获取字节码文件对象
Class clas = Class.forName("com.study.reflect.Pojo.Student");
//2、创建对象
Student s = (Student) clas.newInstance();
//3、获取成员方法
Method study = clas.getMethod("study");
Method setName = clas.getMethod("setName", String.class);
//4、使用成员方法
study.invoke(s);
setName.invoke(s,"Sam");
System.out.println(s);
}
}
19.5反射的使用场景
需求:通过反射技术,向一个泛型为Integer的集合中添加一些字符串数据
public class Demo {
public static void main(String[] args) throws Exception {
ArrayList<Integer> lst = new ArrayList<>();
lst.add(10);
lst.add(20);
lst.add(30);
//lst.add("abc");//报错
System.out.println(lst);
Class clas = lst.getClass();
//核心代码Object.class
Method add = clas.getDeclaredMethod("add",Object.class);
add.invoke(lst,"abc");//添加字符串成功
System.out.println(lst);
}
}
20、Properties类
Properties集合类介绍:
1)是双列集合,是Hashtable的子类,键和值都是String类型
2)是唯一可以和IO流结合使用的集合类
成员方法:
public void setProperty(String key,String value); //类似Map#put
public String getProperty(String key);//类似Map#get
public void load(InputStream is);
public void load(Reader rd);
public void store(OutputStream os,String conments);
public void store(Writer w,String conments);
示例:
public class PropertiesDemo {
public static void main(String[] args) throws Exception {
Properties pp = new Properties();
pp.setProperty("name","Sam");
pp.setProperty("age","12");
pp.put("phone","88886666");
FileOutputStream fos = new FileOutputStream("my_day15/src/class.properties");
pp.store(fos,"初始化");
fos.close();
}
}
21 注解
定义注解:
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
21.1 元注解
元注解1:@target
•作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用。
–可选的参数值在枚举类ElemenetType中包括:
TYPE: 用在类,接口上
FIELD:用在成员变量上
METHOD: 用在方法上
PARAMETER:用在参数上
CONSTRUCTOR:用在构造方法上
LOCAL_VARIABLE:用在局部变量上
元注解2:@Retention
•作用:定义该注解的生命周期(有效范围)。
–可选的参数值在枚举类型RetentionPolicy中包括
SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。
CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值。
RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解。
代码示例:
//定义注解
@Target({ElementType.TYPE,ElementType.METHOD})//限定次注解只能在类或方法上使用
@Retention(RetentionPolicy.RUNTIME)//限定此注解在代码阶段、编译阶段和运行阶段都有效
public @interface Student {
String name();
int age();
String[] friends();
}
使用注解
@Student(name = "Tom",age = 12,friends = {"Sam","Dalin"})
public class School {
//@Student(name = "xiaoming",age = 13,friends = {"Kai","Sunny"})//此句会报错,因为限定了注解的使用范围,不能在成员变量上使用
String name;
@Student(name = "xiaoming",age = 13,friends = {"Kai","Sunny"})
public void study(){
System.out.println("好好学习,天天向上");
}
}
public class Demo {
public static void main(String[] args) throws Exception {
//一、获取类上的注解
//1、获取字节码文件的对象
Class clas = School.class;
//2、判断注解是否存在
if(clas.isAnnotationPresent(Student.class)){
//3、获取注解
Student s1 = (Student) clas.getAnnotation(Student.class);
System.out.println("name:"+s1.name());
System.out.println("age:"+s1.age());
System.out.println("friends:"+ Arrays.toString(s1.friends()));
}
//二、获取方法上的注解
//1、获取方法对象
Method study = clas.getDeclaredMethod("study");
//2、判断注解是否存在
if(study.isAnnotationPresent(Student.class)){
//3、获取注解
Student s2 = study.getAnnotation(Student.class);
System.out.println("name:"+s2.name());
System.out.println("age:"+s2.age());
System.out.println("friends:"+ Arrays.toString(s2.friends()));
}
}
}