从今天开始,我们将学习java语言中稍微高级的知识点。
进程与线程
进程:是程序(任务)执行过程,持有的资源和线程。
线程:线程是系统执行的最小单元,同一个进程中有多个线程,线程共享进程的资源。
线程交互方式
- 互斥
- 同步
java中线程的展示
- 类 thread
- 接口 runable
停止java线程
错误方法:stop。调用这个方法缺点就是线程戛然而止,突然停止,不知道执行到哪。所以不建议用。
正确方法,在线程中,使用停止标志,控制线程循环。
争用条件
当多个线程同时共享访问同一个数据,每个线程都尝试操作数据,从而导致数据的破坏。如何解决这个问题,要保证每一个线程访问临街数据时,其他线程不能访问,当访问完,通过某个通信机制,告诉其他线程,它做完了。
通过synchronized关键字来实现互斥,通常我们开锁是需要耗费内存资源,所以不要经常开锁,当缺少某些条件的时候,我们采取的方法,可以用while来判断。其中用object.wait().最后执行完之后,可以采用notifyall,来实现了同步的。
wait,notify,notifyll都是object的方法。
java io
文件说到底,还是对字节的操作,一个字节8位,一个字节可以换算成十进制整数,所以可以当做整数处理或者字节数组。
gbk编码:一个中文汉字占两个字节,一个英文字母占一个字节。
utf-8编码:一个中文汉字占3个字节,一个英文字母占一个字节。
java编码:中文和英文字母都是占两个字节。
需要注意的一个字符串按某种编码变成字节码,字节码变成字符串,也必须按照这种编码,否则就是乱码。
file 可以表示文件或者目录
file只能用于获取文件的名称,大小,不可以访问文件内容。
File file = new File("liujinxin.txt");//创建文件,带文件名
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//创建文件
file.getAbsolutePath();//获取文件或者目录的绝对地址。
file.getName();//获取文件名字
file.isFile();//判断是否是文件
File file1 = new File("E:"+File.separator);//创建目录地址,这里需要注意的就是File.separator,不管在任何平台都认识
file1.isDirectory();//判断是否是目录
file1.getName();//获取目录名
System.out.println(file1.exists());//判断文件或者目录是否存在
System.out.println(file1.mkdir());//创建目录
System.out.println(file1.delete());//删除文件或者目录
file.getParent();//获取文件和目录的父类
目录遍历
File file2 = new File("E:"+File.separator);
if(file2.isDirectory()){
String[] filename = file2.list();//需要注意这里是返回当前目录下所有子
//目录的名字,缺点,如果子目录下还有目录就不能遍历
}
if(file2!=null&file2.length()>0){
if(file2.isDirectory()){
File[] file3 = file.listFiles();//虽然这里也是返回子目录的目录对象,但是
//但是由于这返回的是对象,可以在进行递归遍历。
for(File file4:file3){//遍历file3的所有对象
if(file4.isDirectory()){
listdirectory(file4);//在次递归调用方法,进行遍历
}else{
System.out.println(file4);
}
}
}
}
RandomAcessFile
可以对文件内容访问,即可对文件读,也可以写。特点可以随机访问文件,即可以访问文件任意位置。
RandomAccessFile raf = new RandomAccessFile(file2, "rw");//后面参数对文件操作模式,rw代表可读可写
raf.writeInt(13);
byte[] b = new byte[(int) (raf.length())];
raf.read(b);
System.out.println(b);
io流
分为:输入流(用来读的操作),输出流(用来写的操作)。字节流,字符流。
抽象类
- inputstream 实现类 fileinputstream
- outputstream 实现类 fileoutputstream
对于字节流文件操作操作,读到eof=-1,表示文件读取完毕。
网络编程
网络中两台主机互联的条件
- 两台主机地址,就是ip
- 互联的主机必须有相同的协议,否则无法沟通
- 不同主机多个应用程序的相互通信,每一个应用都有唯一的端口号,所以要使用端口号区分
InetAddress
这个类用于标识网络上硬件资源。
InetAddress adress = InetAddress.getLocalHost();//获取本机的Inetadress实例
String name = adress.getHostName();//获取本机名字
String ip = adress.getHostAddress();//获取本机的ip地址
InetAddress otheradress = InetAddress.getByName(name);//根据其他主机名字获取实例
String name = adress.getHostName();//获取其他主机名字
String ip = adress.getHostAddress();//获取其他主机的ip地址
InetAddress adress = InetAddress.getByName(ip);//可以根据ip地址来获取主机信息
url
统一资源定位符
URL url = new URL("http://wwww.baidu.com");//创建url实例
String protocol= url.getProtocol();//获取url协议
String host = url.getHost();//获取url主机名
int port = url.getPort();
String query = url.getQuery();//返回url带的参数的查询语句。
利用url访问html内容
URL url1 = new URL("http://www.baidu.com");
InputStream in = url1.openStream();//获取url的输入流
InputStreamReader ins = new InputStreamReader(in);//将字符流转成字节流
BufferedReader br = new BufferedReader(ins);
String data = br.readLine();
while(data!=null){
System.out.println(data);
data = br.readLine();
}
br.close();
ins.close();
in.close();
socket
- tcp 面向连接,可靠,有序的字节流。
基于tcp的socket通信
客户端
try {
Socket s = new Socket("ip",8888);//指定服务器的IP地址和端口号
OutputStream os = s.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("内容");
s.shutdownOutput();//关闭输出流
pw.flush();//刷新缓冲,输出
pw.close();
os.close();
s.close()
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
服务端
try {
ServerSocket ss = new ServerSocket(8888);//创建服务器的socket,指定端口
Socket s = ss.accept();//接受客户端连接,返回一个socket对象,accept是阻塞方法,会一直等待客户端的连接。
InputStream in = s.getInputStream();//获取字节输入流
InputStreamReader ins = new InputStreamReader(in);//将字节输入流包装成字符流
BufferedReader bf = new BufferedReader(ins);//将字符流添加到缓冲区
String info = bf.readLine();
while(info!=null){
System.out.println(info);
info = bf.readLine();
}
s.shutdownInput();//关闭输入流
s.close();
bf.close();
ins.close();
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
如果多个客户端来访问服务器,采用的方法就是多线程。
注意上面shutinput,shutoutput方法,是关闭一次流操作,在执行下一次流操作。
- 基于udp的socket
服务器端
try {
DatagramSocket ds = new DatagramSocket(8888);//创建服务器端的
//datagramsocket,并指定端口
byte[] b = new byte[2048];//读取客户端的数据,并保存在数组中
DatagramPacket packet = new DatagramPacket(b, b.length);//指定数据包的大小
ds.receive(packet);//阻塞方法,等待客户端的数据包
String info = new String(b, 0, packet.getLength());
System.out.println(info);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
客户端
try {
InetAddress adress = InetAddress.getByName("");
int port = 8888;
byte[] b ="内容".getBytes();
DatagramPacket packet = new DatagramPacket(b, b.length,adress, port);
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
java反射
类是对象,类是java.lang.class对象。
Class不能创建对象,只能由jvm创建。
我们可以说任意一个类都是Class对象,有三种表达方式
public class Class1 {
public static void main(String[] args) {
Fu fu =new Fu();
1. Class c1 = Fu.class; //知道类名,
2. Class c2 = fu.getClass(); //通过Fu的对象来获取
3. Class c3 = null;
try {
c3 = Class.forName("com.example.java.Fu");//类的全称
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//c1 c2都是成为Fu的类类型
System.out.println(c1==c2);//一个类只能有一个类类型。
System.out.println(c2==c3);
try {
Fu fu1 = (Fu) c1.newInstance();//可以通过类类型去创建该类的实例对象
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Fu{
}
加载类
编译时加载类是静态加载类,运行时加载类是动态加载类。
静态加载类
Fu fu =new Fu();
new对象,就是静态加载,在编译的时候就需要加载所需要的类,否则,不能运行。
动态加载类
public class Office {
public static void main(String[] args) {
Class c = null;
try {
c = Class.forName(args[0]);//获取类类型
Workutil wu = (Workutil) c.newInstance();//通过类类型获取该类的实例对象
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public interface Workutil {//制定接口实现规范
void work();
}
public class Ppt implements Workutil {
public void work() {
// TODO Auto-generated method stub
System.out.println("ppt开始工作啦");
}
}
public class Excel implements Workutil {
public void work() {
// TODO Auto-generated method stub
System.out.println("excel开始工作啦");
}
}
获取类的方法信息
Class c = obj.getClass();//获取obj的类类型对象
System.out.println(c.getName());//返回所有类的方法。
Method[] m = c.getMethods();//这个获取的方法,包括是继承父类的
// c.getDeclaredMethods();//这个获取方法只是自己申明的方法,不包括继承的。
for(int i = 0;i<m.length;i++){
System.out.println(m[i].getName());//返回每一个返回名字
Class returntype = m[i].getReturnType();//获取方法的返回的类型
System.out.println(returntype.getName());//答应返回值类型
Class[] paratyp = m[i].getParameterTypes();//返回参数类型的类类型的数组
for(Class para :paratyp){
System.out.println(para.getName());//打印每一个参数类型
}
}
获取类的成员变量信息
public void getClassField(Object obj){
Class c1 = obj.getClass();
Field[] field = c1.getFields();//获取所有public方法
//c1.getDeclaredFields();获取所有申明的方法
for(int i = 0;i<field.length;i++){
String filename = field[i].getName();//获取字段的名字
Class fileldtype = field[i].getType();//获取字段类型
}
}
获取类的构造方法
public void getClassCon(Object obj){
Class c2 = obj.getClass();
Constructor[] constructor = c2.getDeclaredConstructors();//获取该类的自己申明构造函数的类类型
for(int i = 0;i<constructor.length;i++){
String constructorname = constructor[i].getName();
Class[] constructorparatype = constructor[i].getParameterTypes();//获取该类的构造函数的参数的类类型的数组
for(Class contparaype: constructorparatype){
String paraname = contparaype.getName();//获取构造函数的参数名字
}
}
}
如何获取某个方法
方法对的方法名和参数列表唯一决定了该方法。public class TestMethods {
public static void main(String[] args) {
A a = new A();
Class c = a.getClass(); //获取A的类类型
//a.print(10, 20);//调用方法
Method m;
try {
m = c.getDeclaredMethod("print", int.class,int.class);//传入方法的方法名,后面是方法的参数的类类型
m.invoke(a, 10,20);//通过放射调用方法,第一变量是操作的方法的对象,后面是参数的参数类型
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class A{
public void print(int a,int b){
System.out.println(a+b);
}
}
通过反射来认识泛型
public static void main(String[] args) {
List list = new ArrayList();
list.add(1);//这个list可以添加任意集合
List<String> list1 = new ArrayList<String>();
list1.add("liu");//只能添加字符串集合
//结论:泛型是防止数据的错误输入,在编译前有效,绕过编译就无效。
Class c = list1.getClass();
try {
Method m = c.getDeclaredMethod("add", int.class);
m.invoke(list1, 132);//这样就可以将整型添加进去
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}