文档章节

Java-J2SE专题复习

pmos
 pmos
发布于 2016/05/11 17:46
字数 10408
阅读 119
收藏 4
点赞 2
评论 0

J2SE-->J2EE

由于一些类非常的常用,所以将其放置在java.lang包中,并且自动导入java.lang中的所有类。

1、数组和集合类

1.1、数组

    数组的定义

		//定义了一个num1变量可以存储3个int类型的数字
		int[] num1 = new int[3]; //定义的时候确定大小
		int num[] = new int[4]; //不建议使用
		num1[0] = 10;
		num1[1] = 11;
		num1[2] = 12;
		System.out.println(num1[0]+","+num1[1]+","+num1[2]);
		
		int[] num2 = {13,14,15}; //定义的时候直接赋初始值
		System.out.println(num2[0]+","+num2[1]+","+num2[2]);

    

    数组的遍历

                //num2.length获取数组的长度
		for(int i=0;i<num2.length;i++) {
			System.out.println(num2[i]);
		}

1.2、集合类

    集合类可以提供一些方便的操作来替代数组,集合类都在java.util包中,主要的结构

List简介

 List list = new ArrayList();
  //通过add()添加元素
  list.add("123");
  list.add("234");
  list.add("345");
  list.add("456");
  
  list.remove("345");
  //通过size()可以获取列表的长度,注意size()是方法
  for(int i=0;i<list.size();i++) {
   //通过get()可以获取某一位置的元素
   //get()的元素是Object的,所以需要进行强制类型转换
   String str = (String)list.get(i);
   System.out.println(str);
  }

    以上操作是有风险的

list.add("456");
list.add(111);

    由于是基于Object来添加的,所以也可以添加其它类型的值,这个时候在进行强制类型转换

    的时候,就会抛出异常。

泛型:使用泛型可以有效的解决基于Object添加的问题,泛型是在JDK1.5之后才出现的。

                //使用了泛型后,说明这个list中只能添加String类型的值
		List<String> list = new ArrayList<String>();
		list.add("123");
		list.add("abc");
		list.add("456");
		
		for(int i=0;i<list.size();i++) {
			//使用了泛型,就不用进行强制类型转换了
			String str = list.get(i);
			System.out.println(str);
		}

封装类

对于8种基本数据类型,都提供了相应的封装类来将这些基本数据类型封装为对象。

特别注意:在JDK1.5之后提供了自动的封装和解封装,如果是1.4之前均需要手动解封装。

    

		Integer num1 = 10; //JDK1.5之后提供了自动封装
		Integer num2 = new Integer(10); 
                //JDK1.5之前的版本要创建Integer需要通过构造函数
		
		int num3 = num1; //JDK1.5之后会自动将Integer转换为int
		int num4 = num2.intValue(); 
                //JDK1.5之前需要使用Integer的intValue()方法转换
		
		String str = "123";
		System.out.println(str+1);
		//parseInt是一个static的方法,可以将字符串转换为整型
		int a = Integer.parseInt(str);
		/*
		 * 对于其他封装类而言均有相应的parseXXX来将字符串转换为其它类型的值
		 */
		
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(5);
		//此处如果仅仅使用remove(2)会移除下标为2的元素
                //如果要移除对象需要将2转换为Integer
		list.remove(new Integer(2));

Iterator迭代器

对于所有的集合类,都提供了一个基于迭代器的遍历方式。

    

                //创建一个迭代器,由于Collection通过iterator方法创建迭代器,所以所有集合类都拥有这个方法
		Iterator<String> it = str.iterator();
		//Iterator中有hasNext()来检查元素是否存在
		while(it.hasNext()) {
			//通过next()方法可以获取下一个元素
			String s = it.next();
			System.out.println(s);
		}
		
		/*
		 * Set没有顺序,所以没有get()方法
		 * for(int i=0;i<str.size();i++) {
			String s = str.g
		}*/
		//List也可以使用迭代器
		Iterator<Integer> it = list.iterator();
		for(;it.hasNext();) {
			int num = it.next();
			System.out.println(num);
		}

1、使用迭代器会有一个问题,不太方便获取下标;

2、在列表数据的时侯,需要删除元素时,不建议使用迭代器的方式。

		//List也可以使用迭代器
		Iterator<Integer> it = list.iterator();
		for(;it.hasNext();) {
			int num = it.next();
			//删除时会报错
			/*if(num==3) {
				list.remove(new Integer(num));
			}*/
			System.out.println(num);
		}

在JDK1.5之后又提供一种增强的for循环来遍历列表和数组,原理基于迭代器。

		List<String> strs = new ArrayList<String>();
		strs.add("abc");
		strs.add("def");
		strs.add("ghj");
		//会使用str来遍历集合中的每一个元素
		for(String str:strs) {
			System.out.println(str);
		}
		System.out.println("===============忧伤的分割线===================");
		Set<String> sets = new HashSet<String>();
		sets.add("qwe");
		sets.add("asd");
		sets.add("zxc");
		for(String str:sets) {
			System.out.println(str);
		}
		System.out.println("--------------------傲娇的分割线---------------------");
		Integer[] nums = {2,3,4,5,6,7};
		for(Integer num:nums) {
			System.out.println(num);
		}

Set和List

/*
 * List和Set的区别
 * 1、List有序而Set无序
 * 2、Set不能添加重复的元素,List可以添加重复的元素
 */
public class TestListSet {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("aaaa");
		list.add("bbbb");
		list.add("cccc");
		list.add("dddd");
		list.add("aaaa");
		for(String str:list) {
			System.out.println(str);
		}
		System.out.println("---------------------------------");
		Set<String> set = new HashSet<String>();
		set.add("abcd");
		set.add("acbd");
		set.add("adbc");
		set.add("cabd");
		set.add("abcd");
		for(String str:set) {
			System.out.println(str);
		}
		
		//去掉List中重复的元素
		List<Integer> ls = Arrays.asList(1,2,3,4,5,6,5,4,3,2,1);
//		Set<Integer> ss = new HashSet(ls);
		Set<Integer> ss = new HashSet<Integer>();
		ss.addAll(ls);
		for(Integer num:ss) {
			System.out.println(num);
		}
	}

Map

		//Map存储的是键值对,key和value
		Map<Integer,String> maps = new HashMap<Integer,String>();
		//使用put方法添加值
		maps.put(1, "张三");
		maps.put(2, "李四");
		maps.put(3, "王五");
		maps.put(4, "赵六");
		//使用get(key)可以得到value
		System.out.println(maps.get(3));
		
		//keySet可以将maps中的key转换为Set的一组列表
		Set<Integer> keys = maps.keySet();
		//遍历Set可以得到相应的key,使用maps.get(key)可以得到value
		for(Integer i:keys) {
			System.out.println(maps.get(i));
		}
		
		//此时不会增加,会覆盖
		maps.put(4, "老七");
		System.out.println("----------------------");
		//keySet可以将maps中的key转换为Set的一组列表
		keys = maps.keySet();
		//遍历Set可以得到相应的key,使用maps.get(key)可以得到value
		for(Integer i:keys) {
			System.out.println(maps.get(i));
		}
		
		System.out.println(maps.containsKey(4));
		System.out.println(maps.containsValue("老七"));

2、异常处理

使用异常的原因

传统的处理方式是使用if else来进行判断,这样将会有大量的if嵌套,会严重影响代码的编写效率和可读性。

Java的异常处理方式

try {
    //把可能发生异常的代码放到try语句块中
} catch() {  //为不同的异常使用不同的catch来进行捕获
} catch() {
} catch() {

}

2.1、异常的概念

Java中所有的异常都是class,并且都继承于Exception。

异常都是对象,有两个重要的方法。

		try {
			result = a/b;
			System.out.println("有异常,这里不输出!");
		} catch(ArithmeticException e) {
			//打印相应的异常错误信息,message是exception的一个属性
			System.out.println(e.getMessage());
			//打印异常发生的轨迹
			e.printStackTrace();
		}

2.2、异常的产生

异常全部都是类,它是通过在代码中使用throw抛出的。

2.3、异常的创建

写一个类让其继承Exception。

//写一个类继承Exception
public class MyException extends Exception {
	
	//覆盖父类的构造方法
	public MyException() {
		super();
	}

	public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public MyException(String message, Throwable cause) {
		super(message, cause);
	}

	public MyException(String message) {
		super(message);
	}

	public MyException(Throwable cause) {
		super(cause);
	}

2.4、异常的处理

有两种方式可以处理异常

1、try catch

2、声明为抛出(声明方法会有异常,方法上面的异常声明使用异常的类型来声明)

非运行时刻异常,需要程序员手动处理。

		try {
			//此处依然会有异常,如果不处理,需要在main函数上声明抛出,
			//但是强烈建议不要在main函数上面抛出异常
			buyCoffeeAndWater(-300,500);
			buyWater(1);
			buyCola(-1);
		} catch (MyException e) {
			System.out.println(e.getMessage());
		} catch (MyRunException e) {
			System.out.println(e.getMessage());
		}
	}
	
	//方法上面是声明该方法可能产生的异常
	public static void buyWater(int size) throws MyException {
		//非运行时刻异常,不会自动抛出,得程序员手动处理
		if(size<0) {
			//此处抛出的是一个异常对象
			throw new MyException("瓶里没水了!!!");
		}
		System.out.println("买了一瓶"+size+"ml的水");
	}

运行时刻异常

	public static void buyCola(int size) {
		if(size<0) {
			//运行时刻异常,不用程序员手动处理,虚拟机会自动抛出
			throw new MyRunException("可乐过期了!!!");
		}
		System.out.println("买了一瓶"+size+"L的可乐");
	}

2.5、异常的多态

	//抛出异常可以通过多态来处理
	public static void buyCoffeeAndWater(int coffeeSize,int waterSize) throws Exception {
		if(coffeeSize<0) {
			throw new MyException2("咖啡凉了!!!");
		}
		if(waterSize<0) {
			throw new MyException("水喝完了");
		}
		System.out.println("买了一杯"+coffeeSize+"ml的咖啡和一瓶"+waterSize+"ml的水");
	}
		try {
			buyCoffeeAndWater(-300,500);
			buyWater(1);
			buyCola(-1);
			//捕获和抛出异常都支持多态,
			//但是捕获顺序如果先捕获了父类异常就无法再捕获子类异常了
		} catch (MyException e) {
			System.out.println(e.getMessage());
		} catch (MyRunException e) {
			System.out.println(e.getMessage());
		} catch (MyException2 e) {
			System.out.println(e.getMessage());
		} catch (Exception e) {
			System.out.println(e.getMessage());

2.6、finally

finally是不管怎么样都会被执行的代码,所以一般用来释放资源。

		} catch (Exception e) {
			System.out.println(e.getMessage());
		} finally {
			//finally语句块中的内容不管怎么样都会被执行
			//所以finally中的代码一般用来释放资源
			System.out.println("一直运行");
		}
		//可以不要catch直接加finally
		try {
			System.out.println("hello");
		} finally {
			System.out.println("可以运行");
		}

3、I/O

File类:用来处理文件夹和创建删除文件的,不能用来编辑文件。

常用方法:

			//创建文件
			f.createNewFile();
			//判断文件是否存在
			System.out.println(f.exists());
			//删除文件
			//f.delete();
			//获取文件名
			System.out.println(f.getName());
			//获取文件夹路径
			System.out.println(f.getParent());
			//可以获取该文件的父类文件夹对象
			File pf = f.getParentFile();
			//判断文件是否是文件夹
			System.out.println(pf.isDirectory());
			
			File f2 = new File("d:/test/a");
			//创建一个目录
			f2.mkdir();
			File f3 = new File("d:/test/b/c/d/e/f");
			//如果父目录不存在,会先创建父目录再创建相应的子目录
			f3.mkdirs();
			//如果删除的是目录,目录不为空就无法删除
			/*
			 * 正确删除文件夹的操作是递归删除所有的文件和子文件夹
			 */
			f3.delete();
			//重命名文件--->可以用来做剪切,但是不建议使用
			f.renameTo(new File("d:/test/a/1.txt"));

文件列表:

		//list()用来列表一组文件名,可以传入一个实现FilenameFilter的类完成文件的过滤
		String[] fns = f.list(new JavaFileFilter());
		for(String fn:fns) {
			System.out.println(fn);
		}
		System.out.println("------------------------");
		//列表一组文件对象
		File[] fs = f.listFiles();
		for(File file:fs) {
			System.out.println(file.getName()+":"+file.length());
		}
	}
}

/**
 * 写一个类实现FilenameFilter专门用来过滤文件
 * @author PM
 *
 */
class JavaFileFilter implements FilenameFilter {
	@Override
	public boolean accept(File dir, String name) {
		// 过滤的结果是返回为true的值
		if(name.endsWith(".java")) return true;
		return false;
	}
}

内部类:有些类在外部是不被允许访问的,可以把这些类写在类的内部,提高安全性。

普通内部类:

	public void run() {
		//在非static的方法中才能访问内部类
		File f = new File("D:\\test\\j2se");
		String[] fns = f.list(new JavaFileFilter());
		for(String fn:fns) {
			System.out.println(fn);
		}
		System.out.println("------------------------");
	}
	
	
	/**
	 * 如果这个类仅仅只是在某个类的内部可以访问,可以直接将该类写在类的内部
	 * 这个类在外部就无法访问,这种类叫做内部类.
	 * 内部类要在static之后才能声明,所以不能在static的方法中使用内部类
	 * @author PM
	 *
	 */
	private class JavaFileFilter implements FilenameFilter {
		@Override
		public boolean accept(File dir, String name) {
			// 过滤的结果是返回为true的值
			if(name.endsWith(".java")) return true;
			return false;
		}

匿名内部类:

		File f = new File("D:\\test\\j2se");
		/**
		 * 匿名的内部类,该类没有名称,是在代码返回之前就给它实现了
		 * 这种方式存在的唯一意义就是只有一个方法会涉及到该类才建议这样写
		 * 如果有两个或者多个方法会使用,均建议使用内部类
		 */
		String[] fns = f.list(new FilenameFilter(){//实现的开始
			//特别注意:是在语句返回之前就完成了实现的
			@Override
			public boolean accept(File dir, String name) {
				if(name.endsWith(".java")) return true;
				return false;
			}
		});//实现的结束
		for(String fn:fns) {
			System.out.println(fn);
		}

过滤文件夹:

		File[] fs = f.listFiles(new FileFilter(){
			//过滤文件夹,可以使用FileFilter,操作方式和FilenameFilter类似
			@Override
			public boolean accept(File pathname) {
				if(pathname.isDirectory()) return true;
				return false;
			}
			
		});

流的分类:按照方向分类、按照类型分类、按照操作方式分类、转换流。

按照方向分类:输入流、输出流。

输入流:这是一个字节流操作的非常标准过程

		FileInputStream fis = null;
		try {
			//1、创建一个文件输入流
			fis = new FileInputStream("D:\\test\\j2se\\aaa.txt");
			//2、创建一个字节数组用来存储读取的信息
			byte[] buf = new byte[1024];
			//3、使用len读取的长度
			int len = 0;
			//4、循环读取数据
			//只要len>=0说明就读取到元素,可以直接对元素进行操作
			while((len=fis.read(buf))>=0) {
				//5、通过控制台输出数据,必须说明输出的长度
				//如果输出文件乱码,要修改文件输入流编码格式与输出格式编码一致
				System.out.write(buf, 0, len);
			}
			//6、读取完成之后必须关闭流释放资源
			fis.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				//在这个位置关闭流
				if(fis!=null) fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

输出流:

		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream("D:\\RmDownloads\\WeChat2.0.exe");
			//创建一个文件输出流
			fos = new FileOutputStream("D:\\test\\j2se\\mm.exe");
			byte[] buf = new byte[1024];
			int len = 0;
			//将数据通过输入流读取到程序
			while((len=fis.read(buf))>=0) {
				//将数据通过输出流输出,此时是一个文件输出流,就把数据输出到了文件
				fos.write(buf,0,len);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(fis!=null) fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if(fos!=null) fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

按照类型分类:字节流、字符流

字节流:通过字节读取数据,通常是通过XXXStream

字符流:通过字符来读取数据,Writer和Reader

只要处理的数据是字符数据,全部使用字符流。

		BufferedReader br = null;
		PrintWriter out = null;
		try {
			/*字符流用来读取字符数据,对于输入字符流而言,最为常用操作方法是使用BufferedRead
			 * 因为该流有一个readLine()方法
			 */
			br = new BufferedReader(new FileReader("D:\\test\\read.txt"));
			//BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\test\\1.txt"));
			out = new PrintWriter(new BufferedWriter(new FileWriter("D:\\test\\1.txt")));
			String str = null;
			//BufferedReader中有一个方法叫做readLine()
			//可以一行一行的读取数据并且返回字符串
			while((str=br.readLine())!=null) {
				System.out.println(str);
				//使用bw输出不会换行,得再调用bw.newLine()才能换行
				//bw.write(str);
				//bw.newLine();
				//对于字符流而言,读数据用BufferedReader,写数据用PrintWriter
				out.println(str);
			}
			//bw.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(br!=null) br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if(out!=null) out.close();
		}

按照操作方式分类:节点流、过滤流

节点流:可以直接创建的流

过滤流:可以装饰节点流,增加相应的功能

		FileInputStream fis = null;
		//过滤流不能独立的创建对象,过滤流都需要依赖于已经创建好的节点流
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			fis = new FileInputStream("D:\\RmDownloads\\WeChat2.0.exe");
			//在文件输入流的基础上创建一个缓存流,以此提高效率
			bis = new BufferedInputStream(fis);
			//输出流也可以用过滤流
			bos = new BufferedOutputStream(new FileOutputStream("D:\\test\\j2se\\11.exe"));
			byte[] buf = new byte[1024];
			int len = 0;
			while((len=bis.read(buf))>=0) {
				bos.write(buf,0,len);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			/*
			 * 对于缓冲流一定要关闭,不然如果缓冲区不满就不会刷新,
			 * 很多时候就没有值,可以通过bos.flush()刷新缓冲区
			 */
			//当关闭流的时候会自动flush
			try {
				if(bis!=null) bis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if(bos!=null) bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

转换流:将字节流转换为字符流    InputStreamReader  OutputStreamWriter

		BufferedReader br = null;
		try {
			//把字节流转换为字符流,方便进行字符的处理
			br = new BufferedReader(new InputStreamReader(System.in));
			String str = null;
			while((str=br.readLine())!=null) {
				if(str.equals("exit")) break;
				System.out.println(str);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(br!=null) br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

流的操作

字节流的常用操作:

读:

			byte[] buf = new byte[1024];
			int len = 0;
			//将数据通过输入流读取到程序
			while((len=fis.read(buf))>=0) { //将数据都入到缓冲区
				//将数据通过输出流输出,此时是一个文件输出流,就把数据输出到了文件
				fos.write(buf,0,len);
			}

写:

				//将数据通过输出流输出,此时是一个文件输出流,就把数据输出到了文件
				fos.write(buf,0,len); //写的长度一定要加

字符流的常用操作:

读数据使用BufferedRead,因为有readLine()方法,写数据使用PrintWriter,可以使用println.

具体使用参照字符流的操作介绍。

标准流的常用操作:

System.in是标准输入流,但是由于是字节流,不方便操作,所以通常情况会将其转换为字符流

来处理,通过转换流转换,然后再使用BufferedReader来封装。

		BufferedReader br = null;
		try {
			//把字节流转换为字符流,方便进行字符的处理
			br = new BufferedReader(new InputStreamReader(System.in)); //标准输入流
			String str = null;
			//一行一行的读取数据,并且输出输入的数据
			//直到数据是exit表示退出
			while((str=br.readLine())!=null) {
				if(str.equals("exit")) break;
				System.out.println(str);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(br!=null) br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

常用流

文件流(File):非常常用,进行文件的读写操作

缓冲流(Buffered):过滤流用来提高效率的

数据流:用来读取基本数据类型DataOutputStream和DataInputStream,数据流是过滤流

		FileOutputStream fos = null;
		DataOutputStream dos = null;
		DataInputStream dis = null;
		try {
			fos = new FileOutputStream("D:\\test\\j2se\\num.data");
			//如果希望存储基本数据类型就使用DataOutputStream,也是过滤流
			dos = new DataOutputStream(fos);
			dos.writeInt(1231231231);
			dos.writeInt(1111);
			dos.writeInt(2222);
			dos.writeInt(3333);
			dos.writeInt(4444);
			dos.writeInt(5555);
			//从文件读取基本数据类型使用DataInputStream,同样是过滤流
			dis = new DataInputStream(new FileInputStream("D:\\test\\j2se\\num.data"));
			int a = dis.readInt();
			System.out.println(a);
			//通过一个指针在文件中读取
			System.out.println(dis.readInt());
			System.out.println(dis.readInt());
			System.out.println(dis.readLong());
			System.out.println(dis.readInt());
			//System.out.println(dis.readInt()); //读到头就会报错
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(dos!=null) dos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

对象流(Object):对象流可以完成对对象的存储。

1、必须实现Serializable接口

/**
 * 如果希望把一个对象通过ObjectOutputStream写到文件中,
 * 这个对象必须实现Serializable接口
 * 该接口没有任何方法,只是告诉java可以存储该对象
 * @author OS
 *
 */
public class Student implements Serializable {
	private static final long serialVersionUID = 5839862437697748379L;
	private int id;
	private String name;
	//只要一个属性通过transient设置之后这个属性就不会被存储
	private transient int money;

2、可以把一些属性设置为transient,此时这个属性就不会被存储

	//只要一个属性通过transient设置之后这个属性就不会被存储
	private transient int money;

读取和存储对象可以使用ObjectOutputStream和ObjectInputStream读取,如果要从文件中读取,需要用这两个流封装一下文件流。

		ObjectOutputStream oos = null;
		try {
			//创建一个文件输出流,并且把这个对象输出到文件stu.save中去
			oos = new ObjectOutputStream(new FileOutputStream("d:/test/stu.save"));
			//直接将对象写到文件中
			//注意:对象必须实现Serializable接口
			oos.writeObject(stu);

4、GUI

Frame和JFrame

1、Frame:Frame是整个图用户界面的主要窗口,这个是基于awt的。

		//所有的组件都是放在frame中的
		Frame frame = new Frame();
		//设置标题
		frame.setTitle("hello world");
		//设置窗口大小
		frame.setSize(200, 100);
		//设置窗口位置
		frame.setLocation(100, 100);
		//将窗口显示
		frame.setVisible(true);
		//注意:无法关闭窗口

2、JFrame

/**
 * JFrame的操作和Frame的操作基本一样,但是这个是基于swing这个包的
 * @author os
 *
 */
//基于Swing的图形组件都是以J开头的,操作方式和awt基本类似
public class TestJFrame extends JFrame {
	public static void main(String[] args) {
		new TestJFrame();
	}
	
	public TestJFrame() {
		this.setTitle("sdfdsfds");
		this.setSize(200, 200);
		this.setLocation(200, 200);
		this.setBackground(Color.RED);
		//JFrame提供这个方法来关闭窗口
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);

3、常见的编写方式

/**
 * 对于Frame的编程而言,比较常用的方式是继承Frame类
 * 并且在构造函数或者新编写一个函数来设置Frame的信息
 * @author os
 *
 */
public class TestFrame02 extends Frame {
	public static void main(String[] args) {
		new TestFrame02();
	}
	
	//在这个方法中来设置相应的窗口属性
	public TestFrame02() {
		this.setTitle("hello xm");
		this.setSize(200, 200);
		this.setLocation(300, 500);
		this.setVisible(true);

4、添加组件:所有的图形组件都可以在容器上通过add添加

public class TestJButton extends JFrame {
	//常用的编写方式是,统一把相应的容器组件设置为属性
	private JButton jb1,jb2;
	public static void main(String[] args) {
		new TestJButton();
	}
	
	public TestJButton() {
		this.setTitle("按钮测试");
		this.setSize(500, 500);
		this.setLocation(100, 100);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		//创建两个按钮
		jb1 = new JButton("hello");
		jb2 = new JButton("world");
		//将按钮加到frame中
		this.add(jb2);
		this.add(jb1);
		
		this.setVisible(true);

布局

BorderLayout:Frame的默认布局是BorderLayout

直接执行add方法,默认会添加到center中。

	public TestBorderLayout() {
		this.setTitle("按钮测试");
		this.setSize(500, 500);
		this.setLocation(100, 100);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		//设置该Frame的布局为BorderLayout,默认布局就是BorderLayout。
		//但是如果希望设置垂直和水平间距,需要创建一个BorderLayout设置。
		this.setLayout(new BorderLayout(10,5));
		//创建两个按钮
		jb1 = new JButton("北方");
		jb2 = new JButton("南方");
		jb3 = new JButton("西方");
		jb4 = new JButton("东方");
		jb5 = new JButton("正中");
		//将按钮加到frame中
		//第二个参数用来设置这个组件放置到哪个位置
		this.add(jb1,BorderLayout.NORTH);
		this.add(jb2,BorderLayout.SOUTH);
		this.add(jb3,BorderLayout.WEST);
		this.add(jb4,BorderLayout.EAST);
		this.add(jb5,BorderLayout.CENTER);
		
		this.setVisible(true);

FlowLayout

	public TestFlowLayout() {
		this.setTitle("测试按钮");
		this.setSize(500, 500);
		this.setLocation(100, 100);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//FlowLayout是通过流式布局来显示组件,第一个参数是对齐方式
		//第二个参数是水平间距,第三个参数是垂直间距
		this.setLayout(new FlowLayout(FlowLayout.CENTER,20,30));
		jb1 = new JButton("添加");
		jb2 = new JButton("修改");
		jb3 = new JButton("删除");
		jb4 = new JButton("列表");
		jb5 = new JButton("查询");
		this.add(jb1);
		this.add(jb2);
		this.add(jb3);
		this.add(jb4);
		this.add(jb5);
		
		this.setVisible(true);
	}

GridLayout

	public TestGridLayout() {
		this.setTitle("表格布局");
		this.setSize(500, 500);
		this.setLocation(100, 100);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//表格布局,一共两行三列
		this.setLayout(new GridLayout(2, 3,10,15));

常见简单布局和常用组件

JPanel:用JPanel可以完成特定的布局,JPanel是一个容器对象,可以添加元素和设定布局,

默认布局是FlowLayout。

		this.setTitle("用户登录");
		this.setSize(320, 150);
		this.setLocation(100, 100);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setResizable(false);
		//三个JPanel,每个JPanel中放置不同的元素
		//整个frame是GridLayout
		this.setLayout(new GridLayout(3, 1));

JLabel:文本标签只能使用JLabel。

JTextField:文本域组件,可以输入内容。

初始化时可以定义有多少个字符。

		jtf = new JTextField(20);

JPasswordField:密码域,操作和JTextField类似,只是输入的是密码。

JTextArea和JScrollPane

JTextArea:表示多行文本域。

JScrollPane:表示滚动条,在GUI中滚动条需要自己定义。

		jta = new JTextArea();
		//创建滚动条时直接将需要滚动的对象通过构造函数传入
		jsp = new JScrollPane(jta);
		//直接添加滚动条就等于添加了滚动条中的组件
		this.add(jsp);

JComboBox:表示下拉列表框。

传入一个对象数组:

		jcb = new JComboBox<String>(new String[]{"ABC","DEF","GHI"});

菜单的操作

JMenuBar   JMenu    JMenuItem

事件处理

窗口事件:

//定义了一个监听器的类,专门用来实现WindowListener
class MyWindowListener implements WindowListener {

	@Override
	public void windowOpened(WindowEvent e) {
		System.out.println("Opened");
	}

	@Override
	public void windowClosing(WindowEvent e) {
		System.out.println("Closing");
		System.exit(0);
	}
		//为frame添加窗口监听事件,此时,当窗口发生改变时,会自动执行相应的操作
		frame.addWindowListener(new MyWindowListener());

内部类实现

	public TestFrameEvent01() {
		this.setTitle("hello");
		this.setSize(200, 200);
		this.setLocation(100, 100);
		this.addWindowListener(new MyWindowListener());
		this.setVisible(true);
	}
	
	//由于这个类其实没有任何被外部所访问的意义,所以直接使用内部类
	class MyWindowListener implements WindowListener {

适配器

	//如果直接实现WindowListener,会导致实现里面的所有方法,但是很多方法都没用,
	//此时JAVA就提供了一种适配器(Adapter)的方案来解决这种问题,
	//每一个监听器接口都存在一个适配器的类,这个类中对所有的方法进行空的实现
	class MyWindowListener extends WindowAdapter {

		@Override
		public void windowClosing(WindowEvent e) {
			System.out.println("Closing");
			System.exit(0);
		}

匿名内部类

		//WindowListener除了关闭之外,其它地方都用不到,可以直接设置为匿名内部类
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

ActionListener:ActionListener事件是按钮按下的事件。

	//没有adapter,因为只有一个需要实现的方法,actionPerformed()
	class MyBtnListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			System.out.println("aaa");
		}
	}
		jb1 = new JButton("登录");
		jb1.addActionListener(new MyBtnListener());
		jb2 = new JButton("取消");
		jb2.addActionListener(new MyBtn2Listener());

事件的统一处理方式

	class MyBtnListener implements ActionListener {

		@Override
		//定义一个事件监听类,通过参数e.getSource()来获取事件源,
		//并且进行判断做不同的处理
		public void actionPerformed(ActionEvent e) {
			//e.getSource()可以获取哪个监听对象触发事件
			//System.out.println(e.getSource());
			if(e.getSource()==jb1) {
				//System.out.println("login");
				System.out.println("Username:"+jtf.getText());
				System.out.println("Password:"+new String(jpf.getPassword()));
			} else if(e.getSource()==jb2) {
				//System.out.println("cancel");
				jtf.setText("");
				jpf.setText("");
			}



		//相同的监听对象
		jb1 = new JButton("登录");
		jb1.addActionListener(new MyBtnListener());
		jb2 = new JButton("取消");
		jb2.addActionListener(new MyBtnListener());

键盘事件:KeyListener是键盘事件

	private class MyKeyEvent extends KeyAdapter {
		@Override
		public void keyPressed(KeyEvent e) {
			super.keyPressed(e);
			//e的getKeyCode用来获取究竟按下了哪一个键
			//KeyEvent对象的一组常量可以获取具体的键
			if(e.getKeyCode()==KeyEvent.VK_UP) {
				System.out.println("上");
			} else if(e.getKeyCode()==KeyEvent.VK_DOWN) {
				System.out.println("下");
			} else if(e.getKeyCode()==KeyEvent.VK_LEFT) {
				System.out.println("左");
			} else if(e.getKeyCode()==KeyEvent.VK_RIGHT) {
				System.out.println("右");
			}



		//为窗口增加这个事件
		this.addKeyListener(new MyKeyEvent());

绘图

步骤:

1、创建一个内部类继承JPanel

	private class MyPanel extends JPanel {
		//覆盖paint方法
		@Override
		public void paint(Graphics g) {
			super.paint(g);
			g.setColor(Color.BLACK);
			g.drawRect(10, 10, 200, 200);
			g.setColor(Color.BLUE);
			g.fillOval(20, 20, 40, 40);
		}
	}

2、覆盖整个JPanel的paint()方法

	private class MyPanel extends JPanel {
		//覆盖paint方法
		//Graphics g 一支画笔,用它来画图
		@Override
		public void paint(Graphics g) {
			super.paint(g);
			g.setColor(Color.BLACK);
			g.drawRect(10, 10, 200, 200);
			g.setColor(Color.BLUE);
			g.fillOval(20, 20, 40, 40);
		}
	}

3、将这个panel添加到Frame中

		mp = new MyPanel();
		this.add(mp);

捕获键盘事件

1、定义一个面板,并且画一个小球

	private class MyPanel extends JPanel {
		//把x和y坐标定义成变量
		private int x;
		private int y;
		
		public MyPanel(int x, int y) {
			//super();
			this.x = x;
			this.y = y;
		}
		
		@Override
		public void paint(Graphics g) {
			super.paint(g);
			g.setColor(Color.RED);
			g.fillOval(x, y, 20, 20);
		}
	} 

2、将画板添加到窗口

		mp = new MyPanel(10,10);
		this.add(mp);

3、为窗口添加键盘事件

	private class MyKeyEvent extends KeyAdapter {
		//监听键盘的按下事件
		@Override
		public void keyPressed(KeyEvent e) {
			//根据键盘的按钮来确定画板中圆球的坐标
			if(e.getKeyCode()==KeyEvent.VK_UP) {			
				mp.y-=5;
			} else if(e.getKeyCode()==KeyEvent.VK_DOWN) {
				mp.y+=5;
			} else if(e.getKeyCode()==KeyEvent.VK_LEFT) {
				mp.x-=5;
			} else if(e.getKeyCode()==KeyEvent.VK_RIGHT) {
				mp.x+=5;
			}

4、重画画板

			//让面板刷新
			mp.repaint();//最重要的步骤,画完之后一定要重画面板

5、完整代码

	public TestMoveCircle() {
		this.setTitle("移动的小球");
		this.setSize(500, 500);
		this.setLocation(100, 100);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		mp = new MyPanel(10,10);
		this.add(mp);
		this.addKeyListener(new MyKeyEvent());
		
		this.setVisible(true);
	}
	
	private class MyKeyEvent extends KeyAdapter {
		//监听键盘的按下事件
		@Override
		public void keyPressed(KeyEvent e) {
			//根据键盘的按钮来确定画板中圆球的坐标
			if(e.getKeyCode()==KeyEvent.VK_UP) {			
				mp.y-=5;
			} else if(e.getKeyCode()==KeyEvent.VK_DOWN) {
				mp.y+=5;
			} else if(e.getKeyCode()==KeyEvent.VK_LEFT) {
				mp.x-=5;
			} else if(e.getKeyCode()==KeyEvent.VK_RIGHT) {
				mp.x+=5;
			}
			//让面板刷新
			mp.repaint();//最重要的步骤,画完之后一定要重画面板
		}
	} 
	
	private class MyPanel extends JPanel {
		//把x和y坐标定义成变量
		private int x;
		private int y;
		
		public MyPanel(int x, int y) {
			//super();
			this.x = x;
			this.y = y;
		}
		
		@Override
		public void paint(Graphics g) {
			super.paint(g);
			g.setColor(Color.RED);
			g.fillOval(x, y, 20, 20);
		}
	} 

5、多线程:多线程指的是有多条分支在同时进行。

5.1、多线程的编写:

第一种方式

一、让一个类继承相应的Thread类,这个类就是多线程的类。

class FirstThread extends Thread {
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println("first:"+i);
		}
	}
}

二、覆盖这个类的run()方法,run()方法中的代码就是基于多线程的代码。

class FirstThread extends Thread {
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println("first:"+i);
		}
	}
}

三、创建这个对象,并且使用start()开启线程(特别注意不是使用run())

	public static void main(String[] args) {
		FirstThread ft = new FirstThread();
		//此处是使用start()来开始启动线程,不是使用run
		ft.start();
		//此时是函数调用
		//ft.run();
		
		for(int i=0;i<100;i++) {
			System.out.println("main:"+i);
		}
	}

第二种方式

实现Runnable接口

	/*
	 * 第二种方式,是让一个实现Runnable接口。并且实现run()方法。
	 */
	class MyThread implements Runnable {

		@Override
		public void run() {
			for(int i=0;i<100;i++) {
				System.out.println("mt:"+i);
			}
		}



	public void begin() {
		/*
		 * 该方式的使用,由于MyThread没有start()方法,
		 * 所以需要将其放置到一个Thread类中运行
		 */
		MyThread mt = new MyThread();
		//放到一个Thread类中
		Thread t = new Thread(mt);
		//依然是使用start()方法启动
		t.start();
		for(int i=0;i<100;i++) {
			System.out.println("main:"+i);
		}

5.2、多线程的名称

class ThirdThread extends Thread {
	//Thread都有一个名称,只要继承Thread就可以调用super的方法设置名称
	public ThirdThread(String name) {
		super(name);
	}
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			//Thread的名称
			System.out.println(this.getName()+":"+i);
		}
	}



	public void begin() {
		/*
		 * 该方式的使用,由于MyThread没有start()方法,
		 * 所以需要将其放置到一个Thread类中运行
		 */
		MyThread mt = new MyThread();
		//放到一个Thread类中,构造函数的第二个参数就是线程的名称
		Thread t = new Thread(mt,"小二");
		t.start();
		for(int i=0;i<100;i++) {
			System.out.println("main:"+i);
		}
	}
	/*
	 * 第二种方式,是让一个实现Runnable接口。并且实现run()方法。
	 */
	class MyThread implements Runnable {

		@Override
		public void run() {
			for(int i=0;i<100;i++) {
				//没有name属性,可以通过Thread.currentThread()来获取当前线程
				System.out.println(Thread.currentThread().getName()+":"+i);
			}
		}

5.3、线程的调度

	public static void main(String[] args) {
		new TestStatus().run();
	}
	
	public void run() {
		MyThread mt = new MyThread("abcde");
		mt.start();
		new MyThread02("dddddddddddd").start();
		/*try {
			//一直等待该线程执行完才去执行其他线程
			mt.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}*/
		for(int i=0;i<20;i++) {
			System.out.println("main:"+i);
			Thread.yield();
		}
	}
	
	class MyThread extends Thread {
		public MyThread(String name) {
			super(name);
		}
		@Override
		public void run() {
			for(int i=0;i<10;i++) {
				System.out.println(this.getName()+":"+i);
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	class MyThread02 extends Thread {
		public MyThread02(String name) {
			super(name);
		}
		@Override
		public void run() {
			for(int i=0;i<100;i++) {
				System.out.println(this.getName()+":"+i);
			}
		}
	}

5.4、两种线程的区别

	public void run() {
		//每个成员变量都有不同的存储空间
		MyThread mt1 = new MyThread("mt1");//每个线程都是独享相应的存储空间
		mt1.start();
		MyThread mt2 = new MyThread("mt2");//每个线程都是独享相应的存储空间
		mt2.start();
		/*for(int i=0;i<10;i++) {
			System.out.println("main:"+i);
		}*/
	}
	
	class MyThread extends Thread {
		private int index = 0;//每个线程都是独享相应的存储空间
		public MyThread(String name) {
			super(name);
		}
		@Override
		public void run() {
			for(;index<10;index++) {
				System.out.println(Thread.currentThread().getName()+":"+index);
			}
		}




	public void run() {
		//共享mt的成员变量
		//只有一个MyThread对象,所以每个线程都是共享这个MyThread类的空间的
		MyThread mt = new MyThread();
		new Thread(mt,"mt1").start();
		new Thread(mt,"mt2").start();
		/*for(int i=0;i<10;i++) {
			System.out.println("main:"+i);
		}*/
	}
	
	private class MyThread implements Runnable {
		//只有一个MyThread对象,所以每个线程都是共享这个MyThread类的空间的
		private int index;
		@Override
		public void run() {
			for(;index<10;index++) {
				System.out.println(Thread.currentThread().getName()+":"+index);
			}
		}

5.5、线程的停止

	public void run() {
		MyThread mt = new MyThread();
		Thread tmt = new Thread(mt);
		tmt.start();
		while(true) {
			if(mt.index>=500) {
				System.out.println("----");
				//让线程停止
				mt.stopThread();//调用停止的方法
				break;
			}
		}
	}
	
	class MyThread implements Runnable {
		int index = 0;
		//通过一个变量来控制线程的停止
		private boolean flag = true;
		@Override
		public void run() {
			for(index=0;index<1000;index++) {
				if(!flag) {
					break;
				}
				System.out.println("index:"+index);
			}
		}
		
		public void stopThread() {
			//在这个位置释放资源
			flag = false;//通过这个变量控制线程的停止
		}
	}

5.6、线程的同步

		//同步方法,默认使用this作为钥匙
		public synchronized void getMoney() {
			//也可以直接使用this来作为钥匙,任何一个对象都可以做钥匙
			//synchronized (this) {
				System.out.println(Thread.currentThread().getName()+"取了"+getMoney+"元");
				curMoney+=getMoney;
				//当两个线程同时修改某个变量时就会出现同步的问题,
				//需要使用同步块进行同步。
				//如果使用同步块会影响效率
				int temp = saveMoney - getMoney;
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				saveMoney = temp;
				times++;
				System.out.println("3:"+times);
			//}
		}
		
		/*
		 * 使用同步方法其实就等于
		 * public void getMoney() {
		 *直接传入一个对象作为同步块的钥匙
			synchronized (this) {
				System.out.println(Thread.currentThread().getName()+"取了"+getMoney+"元");
				curMoney+=getMoney;
				int temp = saveMoney - getMoney;
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				saveMoney = temp;
				times++;
				System.out.println("3:"+times);
			}
		 */

5.7、死锁

/*
 * 避免死锁的最佳方式,不要出现同步的嵌套,
 * 让同步块尽可能大(效率会降低)
 */
public class TestDeadLock {
	public static void main(String[] args) {
		new TestDeadLock().run();
	}
	
	public void run() {
		MyThread mt = new MyThread();
		new Thread(mt,"张三").start();
		new Thread(mt,"李四").start();
	}
	
	class MyThread implements Runnable {
		private Object k1 = new Object();
		private Object k2 = new Object();
		private boolean flag = true;
		
		@Override
		public void run() {
			if(flag) {
				flag = false;
				synchronized (k1) {
					System.out.println(Thread.currentThread().getName()+":k1");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					synchronized (k2) {
						System.out.println(Thread.currentThread().getName()+":k2");
					}
				}
			} else {
				flag = true;
				synchronized (k2) {
					System.out.println(Thread.currentThread().getName()+":k2");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					synchronized (k1) {
						System.out.println(Thread.currentThread().getName()+":k1");
					}
				}
			}
		}
	}

5.8、生产者和消费者

第一:后台线程

第二:notify和wait

	public void make() {
		synchronized (d) {
			if(d.isEmpty()) {
				int index = ran.nextInt(foods.length);
				String f = foods[index];
				System.out.println(name+"制作了"+f);
				d.setFood(f);
				d.setEmpty(false);
				d.notify();
				try {
					Thread.sleep(2000);
					d.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				/*不能依赖于sleep来控制线程
				 * try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}*/
			} else {
				try {
					d.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}


	public void eat() {
		synchronized (d) {
			if(!d.isEmpty()) {
				String food = d.getFood();
				System.out.println(name+"正在享受"+food);
				d.setEmpty(true);
				d.notify();
				try {
					Thread.sleep(2000);
					d.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				try {
					d.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}


		Disk d = new Disk();
		Cooker co = new Cooker("厨神",d);
		Custom cu = new Custom("吃货",d);
		Thread cot = new Thread(co);
		Thread cut = new Thread(cu);
		//cut为后台线程,只要所有的线程结束,这个线程就自动结束
		cut.setDaemon(true);
		cot.start();
		cut.start();
public class Clock implements Runnable {
	private boolean wakeup;

	public boolean isWakeup() {
		return wakeup;
	}

	public void setWakeup(boolean wakeup) {
		this.wakeup = wakeup;
	}

	public Clock() {
		wakeup = false;
	}
	
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			wake();
		}
	}
	
	public synchronized void wake() {
		try {
			if(!wakeup) {
				for(int i=0;i<3;i++) {
					System.out.println("起床了!");
				}
				wakeup = true;
				this.notify();
				this.wait();
			} else {
				this.wait();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

public class Person implements Runnable {
	private Clock c;

	public Clock getC() {
		return c;
	}

	public void setC(Clock c) {
		this.c = c;
	}

	public Person(Clock c) {
		this.c = c;
	}
	
	@Override
	public void run() {
		while(true) {
			operator();
		}
	}
	
	public void operator() {
		synchronized(c) {
			try {
				if(c.isWakeup()) {
					//System.out.println(c.isWakeup());
					System.out.println("知道了!");
					c.setWakeup(false);
					Thread.sleep(3000);
					c.notify();
					c.wait();
				} else {
					c.wait();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		Clock c = new Clock();
		Person p = new Person(c);
		
		Thread ct = new Thread(c);
		Thread pt = new Thread(p);
		pt.setDaemon(true);
		ct.start();
		pt.start();
		
	}

public class Answer implements Runnable {
	private String name;
	private Asker asker;
	private String[] answers;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Asker getAsker() {
		return asker;
	}

	public void setAsker(Asker asker) {
		this.asker = asker;
	}

	public Answer(String name, Asker asker) {
		this.name = name;
		this.asker = asker;
		answers = new String[]{"好热啊!","大圣,等等我!","上帝笑了!","吃俺老孙一棒!",
				"师傅!师傅","睡觉好舒服!","请你严肃点!","逗你玩!","天亮了!","好好好!"};
	}

	@Override
	public void run() {
		while(true) {
			answer();
		}
	}
	
	public void answer() {
		synchronized (asker) {
			try {
				if(asker.isAsk()) {
					String q = asker.getQuestion();
					if(q.indexOf("王八蛋")>0) {
						System.out.println("你丫才是王八蛋呢!!!");
					} else {
						int index = Asker.ran.nextInt(answers.length);
						String a = answers[index];
						System.out.println(name+":'"+a+"'");
					}
					asker.setAsk(false);
					Thread.sleep(2000);
					asker.notify();
					asker.wait();
				} else {
					asker.wait();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}


public class Asker implements Runnable {
	private String name;
	private String[] questions;
	private String question;
	private boolean isAsk;
	public static Random ran = new Random();
	
	public String getQuestion() {
		return question;
	}

	public void setQuestion(String question) {
		this.question = question;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String[] getQuestions() {
		return questions;
	}

	public void setQuestions(String[] questions) {
		this.questions = questions;
	}

	public boolean isAsk() {
		return isAsk;
	}

	public void setAsk(boolean isAsk) {
		this.isAsk = isAsk;
	}

	public Asker(String name) {
		this.name = name;
		questions = new String[]{"你好吗?","你吃了吗?","你是猴子派来的救兵吗?","你是王八蛋吗?"
				,"今天天气好吗?","中国足球队赢了吗?","朝鲜人民奔小康了吗?","汽油又涨价了吗"};
		isAsk = false;
	}

	@Override
	public void run() {
		for(int i=0;i<20;i++) {
			ask();
		}
	}
	
	public void ask() {
		synchronized (this) {
			try {
				if(!isAsk) {
					int index = ran.nextInt(questions.length);
					question = questions[index];
					System.out.println(name+":'"+question+"'");
					Thread.sleep(2000);
					isAsk = true;
					this.notify();
					this.wait();
				} else {
					this.wait();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}


	public static void main(String[] args) {
		Asker asker = new Asker("春哥");
		Answer ans = new Answer("凤姐",asker);
		Thread ast = new Thread(asker);
		Thread ant = new Thread(ans);
		ant.setDaemon(true);
		ast.start();
		ant.start();
	}

6、网络编程

6.1网络编程步骤

1、建立服务端和客户端

两个类,一个是客户端,一个是服务端

2、编写server端的程序

	public static void main(String[] args) {
		//服务器端就是创建相应的ServerSocket
		ServerSocket ss = null;
		Socket s = null;
		try {
			ss = new ServerSocket(5858);
			//因为服务器端一般都是不停止工作的,所以需要使用死循环
			while(true) {
				try{
					//此处就接收了一个客户端的请求
					s = ss.accept();
					String name = s.getInetAddress().getHostAddress()+":"+s.getPort();
					//System.out.println("a client connect:"+s.getPort()+","+s.getInetAddress());
					BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
					String str = br.readLine();
					System.out.println(name+"--"+str);
					PrintWriter out = new PrintWriter(s.getOutputStream(),true);
					out.println("Receive:"+str);
				} finally {
					if(s!=null) s.close();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				//结束之后要关闭socket
				if(ss!=null) ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

3、创建客户端

	public static void main(String[] args) {
		Socket s = null;
		try {
			/**
			 * 客户端通过Socket连接服务器端
			 */
			s = new Socket("127.0.0.1",5858);
			PrintWriter out = new PrintWriter(s.getOutputStream(),true);
			out.println("你好");
			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			String str = br.readLine();
			System.out.println(str);	
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(s!=null) s.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

4、在服务器端接收客户端的连接

					//此处就接收了一个客户端的请求
					s = ss.accept();
					String name = s.getInetAddress().getHostAddress()+":"+s.getPort();
					//System.out.println("a client connect:"+s.getPort()+","+s.getInetAddress());

5、两端进行通信

服务器端和客户端建立了连接之后可以获取这个Socket的InputStream和OutputStream,

通过这两个流就可以完成相应的操作。

客户端

		try {
			/**
			 * 客户端通过Socket连接服务器端
			 */
			s = new Socket("127.0.0.1",5858);
			//如果要输出字符数据,都是用PrintWriter
			PrintWriter out = new PrintWriter(s.getOutputStream(),true);
			out.println("你好");

服务器的接收端

		try {
			ss = new ServerSocket(5858);
			//因为服务器端一般都是不停止工作的,所以需要使用死循环
			while(true) {
				try{
					//此处就接收了一个客户端的请求
					s = ss.accept();
					String name = s.getInetAddress().getHostAddress()+":"+s.getPort();
					//System.out.println("a client connect:"+s.getPort()+","+s.getInetAddress());
					//只要操作的是字符数据,统一用BufferedReader
					BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
					String str = br.readLine();
					System.out.println(name+"--"+str);

6.2、基于TCP的编程操作

服务端和客户端连接完成之后,通过socket可以完成两段的通信,因为使用socket可以获取相应

的输入流和输出流。

1、建议最佳操作

通过socket获取的输入流或者输出流都是基于字节数据的,所以需要通过基于字节数据的流

完成。

建议在写数据时使用PrintWriter,在读数据时使用BufferedReader。

			/**
			 * 客户端通过Socket连接服务器端
			 */
			s = new Socket("127.0.0.1",5858);
			//如果要输出字符数据,都是用PrintWriter
			//写数据使用PrintWriter
			PrintWriter out = new PrintWriter(s.getOutputStream(),true);
			out.println("你好");



			//读数据使用BufferedReader,通过转换流进行转换
			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			String str = br.readLine();
			System.out.println(str);	

2、服务器端的编写

		//服务器端就是创建相应的ServerSocket
		ServerSocket ss = null;
		Socket s = null;
		try {
			ss = new ServerSocket(5858);
			//因为服务器端一般都是不停止工作的,所以需要使用死循环
			while(true) {
				try{
					//此处就接收了一个客户端的请求
					s = ss.accept();
					String name = s.getInetAddress().getHostAddress()+":"+s.getPort();
					//System.out.println("a client connect:"+s.getPort()+","+s.getInetAddress());
					//只要操作的是字符数据,统一用BufferedReader
					BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
					String str = br.readLine();
					System.out.println(name+"--"+str);
					PrintWriter out = new PrintWriter(s.getOutputStream(),true);
					out.println("Receive:"+str);
				} finally {
					if(s!=null) s.close();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				//结束之后要关闭socket
				if(ss!=null) ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}

6.3、基于UDP的编程操作

UDP通常是通过接收端和发送端完成通信的。

接收端的编写

		DatagramSocket ds = null;
		try {
			//UDP接收端连接
			ds = new DatagramSocket(9999);
			//定义将UDP的数据包接收到什么地方
			byte[] buf = new byte[1024];
			//定义UDP的数据接收包
			DatagramPacket dp = new DatagramPacket(buf, buf.length);
			while (true) {
				//接收数据包
				ds.receive(dp);
				String str = new String(dp.getData(),0,dp.getLength());
				System.out.println(str);
			}

发送端的编写

		DatagramSocket ds = null;
		try {
			//定义一个UDP的Socket来发送数据
			ds = new DatagramSocket();
			//假设发送的数据是个字符串
			String hello = "hello world";
			//定义一个UDP的数据发送包来发送数据,InetSocketAddress表示要接收的地址
			DatagramPacket dp = new DatagramPacket(hello.getBytes(), 
					hello.getBytes().length, new InetSocketAddress("127.0.0.1",9999));
			for(int i=0;i<10;i++) {
				ds.send(dp);
				Thread.sleep(1000);
			}

7、正则表达式

正则表达式是用来处理字符串的。

一、用来进行字符串的匹配。

二、用来进行替换操作。

三、用来提取信息。

7.1、基础表达式

一、基本匹配

.:所有字符

\d:所有数字

\D:所有非数字

\s:空白字符

\S:非空白字符

\w:[a-zA-Z_0-9]

\W:非\w

		//.表示任意字符
		System.out.println("a".matches("."));
		System.out.println("aa".matches(".a"));
		System.out.println("\\d");
		//\\d表示是否是数字
		System.out.println("123".matches("\\d\\d\\d"));
		System.out.println("1a23c4".matches("\\d\\D\\d\\d\\D\\d"));
		//\\s表示是否是空白字符
		System.out.println("1  2		d".matches("\\d\\s\\s\\d\\s\\sd"));
		//\\w表示常用输入字符:a-z,A-Z,0-9,_
		System.out.println("aa b1 22".matches("\\w\\w\\s\\w\\w\\s\\w\\w"));
		//[abcd]表示是否是abcd这四个字符中的某一个
		System.out.println("a".matches("[abcd]"));
		//[a-z]表示是否是a-z之间的字符
		System.out.println("D".matches("[a-zA-Z]"));
		//[^a-z]表示不在a-z之间
		System.out.println("h".matches("[^a-z]"));
		//也支持&&和||
		System.out.println("e".matches("[a-z&&[def]]"));
		System.out.println("H".matches("[a-z]||[A-D]"));

7.2、?*+

二、.、*、+

X?  X,once or not at all

X*  X,zero or more times

X+  X,one or more times

三、范围匹配

X{n}  X,exactly n times

X{n,}  X,at least n times

X{n,m}  X,at least n but not more than m times

[abc]  a,b or c (simple class)

		//*表示任意多个字符(0个或多个)
		System.out.println("aaaa".matches("a*"));
		//输出结果为false,因为*表示的多个
		System.out.println("abcd".matches("a*"));
		System.out.println("abcd".matches("a.*"));
		System.out.println("abcd".matches("a[a-z]*"));
		System.out.println("".matches("a*"));
		//+表示一个或者多个
		System.out.println("aa".matches("a+"));
		System.out.println("a".matches("a+"));
		System.out.println("".matches("a+"));
		//?表示0个或者1个
		System.out.println("a".matches("a?"));
		System.out.println("aa".matches("a?"));
		System.out.println("".matches("a?"));
		//{n,m}表示至少出现n次,最多出现m次
		System.out.println("2016-7-20".matches("\\d{4}-\\d{1,2}-\\d{1,2}"));
		//第一个:检测一个字符串是否是数字
		System.out.println("3423.43".matches("\\d+\\.?\\d+"));
		//第二个:检测一个字符串是否是一个电话号码 010-8898989-01
		System.out.println("0101-2345678-03".matches("\\d{3,4}-\\d{7}-\\d{2}"));
		System.out.println("0101-2345678".matches("\\d{3,4}-\\d{7}-*\\d*"));
		//第三个:匹配一个IP地址:192.168.1.123
		System.out.println("192.168.1.123".matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"));
		//第四个:匹配一个身份证号
		System.out.println("12345678998765432X".matches("\\d{15}||\\d{18}||\\d{17}[X]"));
		//匹配一个电子邮件
		System.out.println("qw@al.com.cn".matches("[\\w-\\.]*\\w+@[\\w\\.-]*\\w+\\.\\w{2,6}"));

7.3、边界处理

		//^不在[]中就表示以xx为开头,特别注意:[^abc]表示除了abc之外的字符
		System.out.println("helloworld".matches("^h\\w+"));
		System.out.println("h".matches("^h\\w+"));
		System.out.println("1you".matches("\\d\\w+"));
		//$表示以XX结尾
		System.out.println("1you1d".matches("\\w*\\d$"));

7.4、Pattern和Matcher

		//可以先将一个正则表达式编译成为一个Pattern对象,可以提高效率
		Pattern p = Pattern.compile("\\d{4}");
		//通过Pattern可以获取一个Matcher对象,通过Matcher对象可以获取大量的有用信息
		Matcher m = p.matcher("23458888-6789-1234");
		//判断是否匹配
		System.out.println(m.matches());
		//将查找的指针重置
		m.reset();
		//以下会报错,必须在find之后才能执行group
		//System.out.println(m.group());
		/*//find指的是顺序匹配相应的字符串
		System.out.println(m.find());
		//每进行一次find,就可以将字符串通过group获取,一定要执行了find之后才能执行group
		System.out.println(m.group());
		System.out.println(m.find());
		System.out.println(m.group());
		System.out.println(m.find());
		System.out.println(m.group());*/
		while(m.find()) {
			//m.start和m.end可以获取匹配字符串的开始位置和结束位置
			System.out.println(m.group()+"["+m.start()+","+m.end()+"]");
		}

7.5、替换

		String str = "23456asdfg2343sdfds343";
		//第一个参数是正则表达式,第二个参数是要替换的值
		System.out.println(str.replaceAll("\\d", "*"));
		System.out.println(str.replaceAll("\\d+", "*"));
		//替换后4位
		System.out.println("12345678909".replaceAll("\\d{4}$", "****"));

7.6、分组和查找

分组

		String str = "222333199812030001,222333199902030002,222333198804050003";
		//使用括号进行分组
		//此处分成了三个组,每一个左括号就是一个组
		Pattern p = Pattern.compile("((\\d{6})(\\d{8}))\\d{4}");
		Matcher m = p.matcher(str);
		while(m.find()) {
			System.out.println(m.group());
			//根据group(xx)来输出某个组的内容
			System.out.println("出生地:"+m.group(2)+"出生日期:"+m.group(3));
		}

贪婪模式

		String h = "<table><td>你好</td><td>我好</td><td>大家好</td></table>";
		//贪婪模式,指的是.*会匹配所有的信息,此处会找整个信息
		p = Pattern.compile("<td>(.*)</td>");
		m = p.matcher(h);
		while(m.find()) {
			//找到的结果:你好</td><td>我好</td><td>大家好
			System.out.println(m.group(1));
			System.out.println(m.start()+","+m.end());
		}

非贪婪模式

		//非贪婪模式,仅仅只是匹配第一个结尾,特别注意:?接在*+之后就表示使用了非贪婪模式
		p = Pattern.compile("<td>(.*?)</td>");
		m = p.matcher(h);
		while(m.find()) {
			System.out.println(m.group(1));
			System.out.println(m.start()+","+m.end());
		}

 

(完)

© 著作权归作者所有

共有 人打赏支持
pmos
粉丝 12
博文 111
码字总数 208836
作品 0
其它
项目经理
Java 8 停止维护,Java 9 难产,IDEA 2018 发布,还有……

祝大家五一劳动节快乐,工作顺利! 又到了总结上个月干货的时候了,这个月我们带来了各种Java技术干货,各种送书抽奖福利,各种面试题分享,各种最新动态资讯等。 - 5.1重磅活动 区块链免费送...

Java技术栈 ⋅ 04/30 ⋅ 0

【目录导航】JAVA零基础进阶之路

【JAVA零基础入门系列】(已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day6 Java字符串 Day7 Java输入与输出...

MFrank ⋅ 06/21 ⋅ 0

sharding-jdbc源码分析—准备工作

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7831817c1da8 接下来对sharding-jdbc源码的分析基于tag为源码,根据sharding-jdbc Features深入学习sharding-jdbc的几个主要特性...

飞哥-Javaer ⋅ 05/03 ⋅ 0

培训云计算学校,虚拟机基本结构讲解

我们要对JVM虚拟机的结构有一个感性的认知。毕竟我们不是编程人员,认知程度达不到那么深入。一个运行时的Java虚拟机实例的天职是:负责运行一个java程序。当启动一个Java程序时,一个虚拟机...

长沙千锋 ⋅ 05/17 ⋅ 0

14、Java并发性和多线程-Java ThreadLocal

以下内容转自http://ifeve.com/java-theadlocal/: Java中的ThreadLocal类可以让你创建的变量只被同一个线程进行读和写操作。因此,尽管有两个线程同时执行一段相同的代码,而且这段代码又有...

easonjim ⋅ 2017/06/16 ⋅ 0

CentOS 6.5 安装JDK(包含卸载原有默认JDK)

卸载原有1.7 JDK 查看是否安装了JDK 若有内容就进一步查看JDK信息 卸载 安装jdk ===================================== 安装wget 新建目录 进入目录 下载JDK 安装JDK 配置环境变量 往文件内...

阿白 ⋅ 05/23 ⋅ 0

Java学习---Java简单认识

前言 小编在学习Java方面的基础知识,发现里面有很多是结合之前的语言的特点发展过来的,不同的地方是,Java有它自己的发展和特点。下面小编先简单地做一下总结,结合看过的1-2章的J2SE视频,...

m18633778874 ⋅ 04/01 ⋅ 0

sharding-jdbc源码解析全集

sharding-jdbc源码解析之词法解析 sharding源码解析之api分析 sharding-jdbc源码解析之spring集成 sharding-jdbc源码解析之spring集成分片构造实现 sharding-jdbc源码解析之jdbc规范重写 sh...

天河2018 ⋅ 05/03 ⋅ 0

深入理解JVM学习笔记(一、总览)

1、JVM历史 2、JVM内存结构 3、JVM垃圾回收机制 4、JVM性能监控工具 5、JVM性能调优案例时间 6、JVM类文件结构 7、JVM类加载机制 8、JVM字节码执行引擎 9、JVM虚拟机编译及其运行时优化 10、...

jintaohahahaha ⋅ 05/28 ⋅ 0

Java就业变难了?你需要对自己有点信心

伴随着IT的火热,越来越多的人进入了IT领域,这在进一步推动着IT发展的同时也极大增加了就业压力。伴随着激烈的岗位竞争,越来越多的人开始感叹工作难找,越火的行业越是如此,Java自是首当其...

糖宝_d864 ⋅ 06/08 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

istio 文档

https://istio.io/docs/concepts/ https://istio.io/docs/concepts/traffic-management/handling-failures/ https://istio.io/docs/concepts/traffic-management/rules-configuration/......

xiaomin0322 ⋅ 14分钟前 ⋅ 0

编程语言的作用及与操作系统和硬件的关系

一、编程语言的作用及与操作系统和硬件的关系 作用:编程语言是计算机语言,是一种程序员与计算机之间沟通的介质,通过编程语言可以使得计算机能够根据人的指令一步一步去工作,完成某种特定...

slagga ⋅ 25分钟前 ⋅ 0

runtime实现按钮点击事件

也不能说是实现吧,,,就是有点类似于RAC里边的写法,不用给btn添加另外的点击事件,就那个add...select...这样子很不友好,来看下代码: [self.btn handleControlEvent:UIControlEventTou...

RainOrz ⋅ 25分钟前 ⋅ 0

Windows系统运维转linux系统运维的经历

开篇之前,首先介绍一下我的背景把:我是一个三线城市的甲方运维。最近,在《Linux就该这么学》书籍的影响下和朋友小A(Linux运维已经三年了,工资也比我的高很多)的影响下,决定转行。最近...

linux-tao ⋅ 26分钟前 ⋅ 0

zip压缩工具,tar打包工具

zip压缩工具 zip打包工具跟前面说到的gzip,bz2,xz 工具最大的不一样是zip可以压缩目录。如果没有安装,需要使用yum install -y zip 来安装。安装完之后就可以直接使用了,跟之前提到的压缩...

李超小牛子 ⋅ 34分钟前 ⋅ 0

使用npm发布自己的npm组件包

一、注册npm账号 官网:https://www.npmjs.com/signup 注册之后需要进行邮箱验证,否则后面进行组件包发布时候会提示403错误,让进行邮箱核准。 二、本地新建一个文件夹,cd进入后使用npm i...

灰白发 ⋅ 35分钟前 ⋅ 0

010. 深入JVM学习—垃圾收集策略概览

1. 新生代可用GC策略 1. 串行GC(Serial Copying) 算法:复制(Copying)清理算法; 操作步骤: 扫描年轻代中所有存活的对象; 使用Minor GC进行垃圾回收,同时将存活对象保存到“S0”或“S...

影狼 ⋅ 36分钟前 ⋅ 0

JVM性能调优实践——JVM篇

在遇到实际性能问题时,除了关注系统性能指标。还要结合应用程序的系统的日志、堆栈信息、GClog、threaddump等数据进行问题分析和定位。关于性能指标分析可以参考前一篇JVM性能调优实践——性...

Java小铺 ⋅ 37分钟前 ⋅ 0

误关了gitlab sign-in 功能的恢复记录

本想关sign-up的,误点了sign-in 退出后登录界面提示: No authentication methods configured 一脸懵逼.. 百度后众多方案说修改application_settings 的 signin_enabled字段; 实际上新版本字段...

铂金蛋蛋 ⋅ 38分钟前 ⋅ 0

登录后,后续请求接口没有带登录cookie可能原因

1.XMLHttpRequest.withCredentials没设置好,参考https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/withCredentials...

LM_Mike ⋅ 38分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部