Java笔记

java 专栏收录该内容
1 篇文章 0 订阅

文章目录

JAVA笔记

JAVA概述

java概述

1>起源

sun公司Green项目hotjava浏览器

2>java特点

简单易学:
    没有c和c++的指针,内存申请和释放
安全性高:
    强类型,垃圾回收机制,禁止非法内存访问。
跨平台:
    作为一种网络语言,其源代码被编译成一种结构中立的中间文件格式。只要有Java运行系统的机器都能执行这种中间代码。
    java源程序被编译成一种与机器无关的字节码格式,在Java虚拟机上运行。硬件操作系统编译器高级语言程序用户
多线程:
即能够使得一个程序同时执行多个任务

3>java虚拟机JVM

4>JVM的平台相关性

java源代码与字节码是与机器无关的,故在装有不同操作系统的机器上,需要有专门为该操作系统开发的JVM,JVM是与机器有关的.

5>java的应用领域

1、J2SE ,主要用来开发桌面应用软件
2、J2ME,嵌入式开发,像手机里的软件,掌上电脑
3、J2EE,属于网络编程,JSP等,

6>学习目标

了解程序语言及发展历史,掌握语法规则,掌握常用类的使用掌握编程逻辑思维能力:会看懂程序,会调试程序,理解并应用面对对象的设计思想。为将来学习J2EE做准备

7>环境变量的设置:


8>classpath的设置

为什么要设置path:
    1、在dos的任何目录下我们都可以运行系统自带的命令;
    2、要想在dos下运行用户自己的程序,则必须进入到改程序的当前目录下方课运行; 
    3、如果希望在dos的任何目录下都可以运行自己创建的程序,则需要我们自己手动设置操作系统自带的环境变量path.
path的设置:
    操作系统是利用path变量来寻找当前程序所存放的路径,并且以最先找到的为准。路径与路径之间用分号;分开。

9>常见dos命令

cd \ 表示进入当前根目录下
cd A\B\C 表示当前目录下的A文件夹下的B文件夹下的C文件夹下面
E: 进入E盘根目录
dir 查看文件夹下文件信息
cls 清屏
javac name.java 编译java文件
java name 运行java文件,即打开.class文件
编译时写文件名,运行时写文件中的类名。故文件的名字和类名最好一样

基础知识

1>Java语言的基本要素——标识符

定义:
程序员对程序中的各个元素加以命名时使用的命名记号称为标识符,
包括:类名、变量名、常量名、方法名、……
规则:
    标识符是以字母,下划线(_)美元符($)开头的一个字符序列,后面可以跟字母,下划线,美元符,数字。
    关键字:abstract default if private

2>数据类型

基本数据类型:
数值型(整数类型(intbyteshortlong)
浮点类型(floatdouble))
字符型(char)
布尔型(boolean)
引用数据类型:(类(class),接口(interface),数组);

3>输出数据的格式控制:

%d( int, long int, short ,byte)
%f(float,double)
%c(char)
%x,%X,%#X,%#x (int long int )
%s (string)
%b (boolean)

4>常量

(1)整型常量:
    十进制,十六进制,八进制
    一个常量整数默认是int类型,如果数字过大,则必须在末尾加L,否则会报错。
    例:long i = 5678678956789//error
    long i = 5678678956789L//ok
(2)浮点型:
    一个实数默认是double类型。如果希望一个实数是float类型,可以在数字后面加f(F)。将一个double类型数值付给float类型变量,编译时会报错。
    例:float x = 2.2//error float x = 2.2f;//ok
(3)字符常量:
    必须用单引号括起来;Java中字符和字符串都用Unicode编码表示;在Unicode编码中一个字符占两个字节。‘a'‘\n' '\uxxxx'特殊字符的常量表示法'\\' '\n'
(4)布尔类型:
    用boolean表示,不能写成bool;布尔型数据只有两个值truefalse,且他们不对应于任何整数值。
    定义:boolean b = true
    只能参与逻辑关系运算:&& || ===

5>不同类型变量的字节

System.out.println("byte所占位数:    "   + Byte.SIZE      + "    -> 1字节");	
System.out.println("short所占位数:   "  + Short.SIZE      + "    -> 2字节");	
System.out.println("int所占位数:      "    + Integer.SIZE  + "    -> 4字节");	//此处不写Int 而写Integer
System.out.println("long所占位数:    "   + Long.SIZE      + "    -> 8字节");		
System.out.println("char所占位数:    "   + Character.SIZE + "  -> 2字节");	//此处不写char 而写Character
System.out.println("float所占位数: "  + Float.SIZE      + "    -> 4字节");	
System.out.println("double所占位数:" + Double.SIZE      + "    -> 8字节");		


6>不同类型的变量相互转换:

一般低字节可以转换成高字节。高字节转换成低字节必须强制转换。
byte b = 10;//1个字节
int i = 6;//4个字节
i = b;//ok b = i;//error 会丢失数据
b =byte)i;//ok 强制类型转化
//b = i;//本语句错误,上面的(byte)i并没有改变i本身的数据类型。

多格式转String
String.ValueOf(各种类型);

int转String
int num1 = 9;
int num2 = 12;
		方法一:
				int num3 = num1 + num2;
				String str3 = num3 + "";
			
		方法二:
				String str3 = Integer.toString(num1 + num2);
		
		方法三:
			  	Integer num3 = num1 + num2 ;
			  	String str3 = num3.toString(num3);
		 
		方法四:
				int num3 = num1 + num2;
				Integer it = new  Integer(num3);
				String str3 = it.toString();
		
	
		方法五:
			String str3 = String.valueOf(num1 + num2);
		 
		 
				
				

String转int
1.
	String str = "1233";
	int i = Integer.parseInt(str);
	//int i = Integer.parseInt("1234");
2.

7>算术运算符:

1)“+”可以表示数值的相加,字符串的联接,也能把非字符转换成字符
    串。System.out.println('a'+1;System.out.println(""+'a'+1;结果98 a1
(2)除法运算符(/)
    跟C语言一样。
(3)取余运算符(%)
    java中允许取余取余运算符的被除数和除数是实数,(与C/C++不同)。但所得余数的正负只和被除数相同。
(4)逻辑与,逻辑或。
    跟C语言一样。
(5)位运算符:(0表示正数,1表示负数)
    &(按位与)把两个数字所有的二进制位相与:1&1=11&0=00&0=00&1=0
    |(按位或)把两个数字所有的二进制位相或:1|1=11|0=10|0=00|1=1
    ~(按位取反)把一个数字的所有二进制位取反。~1=0 ~0=1
    ^(按位异或)把两个数字的所有二进制位异或1^1=01^0=10^0=00^1=1
    >>(右移)C/C++不同,对于有符号数,在右移时,符号位将随同移动,当为正数时,最高位0,最高位补零,而为负数时,最高位为1,最高位补1。移位能让用户实现整数除以或乘以2的n次方的效果。
    >>>(右移)无论最高位是0还是1,左边移空的都补为零。
(6)自增自减
(7)三元运算符boolean b = 20 <= 45 ? true : false;

8>流程控制

(总体同C语言)

1.if 语句分支


2.switch



3.




9>面向过程设计思想

优点: 
    1、分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现。
    2、以算法为核心,
    3、自顶向下设计,要求一开始必须对问题有很深的了解
    4、将大问题转化为若干小问题来求解
    5、表现形式:
        用函数来作为划分程序的基本单位
    6、直接面向问题
缺点:数据和操作分离开,对数据与操作的修改变得很困难;数据的安全性得不到保证;程序架构的依赖关系不合理

10>面向对象的设计思想

1、确定该问题由哪些问题组成!先用类模拟出该事物
2、通过类间接解决问题

12>内存空间分配

[详见 String中的equals ](##### string的equals)

11>printf与println 的区别

import java.lang.String;

class Dian
{
	public int x, y;
	
	public Dian(int x, int y)
	{
		this.x = x;
		this.y = y;
	}

	public String toString()
	{
		return "[" + x + ", " + y + "]";
	}
}


public class TestPrint
{
	public static void main(String[] args)
	{
		Dian d = new Dian(3, 2);
		//System.out.printf("%s\n", d);
		System.out.println(d);
	
		int i, j, k;
		i = 1;
		j = 2;
		k = 3;
		System.out.printf("%d的值 + %d的值 是 %d\n", i, j, k);
		//System.out.println(i + "的值 + " + j + "的值 是 " + k);
		
		int m = 47;
		System.out.println(m);
		System.out.printf("%d\n", m);
		
		System.out.printf("十进制数字%d用十六进制表示是: %#X\n", m, m);
		//System.out.println("十进制数字" + m + "用十六进制表示是: 0X" + Integer.toHexString(m).toUpperCase());
		
		
		System.out.printf("%b\n", "abc".equals("zhangsan"));
		System.out.printf("%d\n", "abc".length());
		System.out.printf("%d\n", "abcadssad".indexOf("ads"));
		
	}
}

12>数组

数组概述
1. 为什么需要数组
        1>为了解决大量同类型数据的存储和使用问题
        2>为了模拟现实世界
2. 什么叫一维数组
        1>为n个变量连续分配存储空间
        2>所有变量的数据类型相同
        3>所有变量所占字节数大小相等
3.数组中的元素可以是基本类型变量,也可以是引用类型变量
一维数组的使用
1.声明的语法格式
       1> 类型 var [];
       2> 类型 [] var;
2. 举例代码:
/*
   一维数组的使用_1
*/

public class TestArray_1
{
   public static void main(String[] args)
   {
   	//方式一
   	int[] arr1;
   	arr1 = new int[3];
   	arr1[0] = 0;
   	arr1[1] = 1;
   	arr1[2] = 2;
   	showArr(arr1);
   	System.out.println("************************");
   	
   	//方式二
   	int[] arr2 = new int[]{0,1,2};
   	showArr(arr2);
   	System.out.println("************************");


/*		System.out.println(arr1);  //error  一维数组的内容是不能通过System.out.println()直
           接输出的,即便该数组的内容是引用且已经重写了toString方法也不行
   
   	int[3] arr3 = new int[]{0,1,2};  //  error
   	int[] arr4 = new int[3]{0,1,2};  //error
   	int[3] arr5 = new int[3]{0,1,2};  //error
*/

   	//方式三
   	int[] arr6 = {0,1,2};  //25行
   	showArr(arr6);
   	System.out.println("************************");
   	arr6 = new int[]{5,4,3,2,1};  //arr6本来是指向25行的{1,2,3}, 但是也可以改变 arr6的值,使其指向{5,4,3,2,1}
   	showArr(arr6);		
   }
   
   public static void showArr(int[] arr)
   {
   	for (int i = 0; i<arr.length; ++i)//length是属性,不是方法,所以这里不加欧豪
   		System.out.println(arr[i]);
   }	
}
4.我的总结:
       数组在整体赋值时[]中不能有数字;
创建并使用引用类型数组
1.代码:
public class Test {
    public static void main (String args[]){
        MvDate [] m;//栈中分配 m 
        m = new MyDate [10];//堆中分配MyDate[]空间,共10 个,均为null
        for(int i=0; i<10; i++){
            m[i]= new Mydate(i+1,i+1,1990+i);
            //i = 0 时;分配Mydate[0],存放 1,1,1990  ,此时MyDate中的第一个null改变,存放Mydate[0]的地址,即指向了Mydate[0]的三个元素
            m[i].dispaly();
        }
    }
}

2.引用类型元素组成的一维数组在使用过程中一般存在着两级的指向关系,这是理解多维不等长数组的基础


多维数组
1.多维数组举例
    1> int [][] aa = new int [2][3];
    2> int [][] aa = {3,2,7},{1,5},{1,6};//不等长数组

                    |-->  3  2  7
    int aa [][] ——  |-->  1  5
                    |-->  6
数组的拷贝
1. 格式:public static void arraycopy(Object arr1, int Pos1, Object arr2, int pos2, int length);
2. 参数:
        arr1 - 源数组
        Pos1 - 源数组中的起始位置
        arr2 - 目标数组//arr2被改变
        pos2 - 目标数据中的起始位置
        length - 要复制的数组元素的数量
3.操作:将arr1 指向的数组中下标从pos1开始的length个元素 "覆盖" 掉arr2指向的数组从pos2开始的length个元素
4.注意:"arraycopy()"方法名中全是小写,不能是大写
5.代码:

public class arraycpoy {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] a = {1, 2, 3, 4, 5};
		int[] b = {-1,-2,-3,-4,-5};
		
		//-1 1 2 -4 -5
		System.arraycopy(a, 0, b, 1, 2); //是arraycopy 不要写成了 arrayCopy 

		System.out.println("a = ");
		for (int i=0; i<a.length; ++i)
		{
			System.out.printf("%d ",a[i]);//(a[i]);
		}
		System.out.printf("\n");
		
		System.out.println("b = ");
		for (int i=0; i<b.length; ++i)
		{
			System.out.printf("%d ",b[i]);
		}

		
	}

}
/*
 * 在jdk11.8中的运行结果是:
--------------------
a = 
1 2 3 4 5 
b = 
-1 1 2 -4 -5 
--------------------
*/

数组排序
1. 方法:
    static void sort(int[] a) 
          对指定的 int 型数组按数字升序进行排序。 
2.代码:
import java.util.*;

public class TestArraysSort_1
{
	public static void main(String[] args)
	{
		int[] data = {1,3,5,7,2,4,6,8,10,9};
		System.out.println("排序前数组data中的内容是:");
		showArray(data);
		
		Arrays.sort(data);
		
		System.out.println("排序后数组data中的内容是:");
		showArray(data);
	}
	
	public static void showArray(int[] data)
	{
		for (int e : data)
			System.out.printf("%d\t", e);
		System.out.println("");
	}
}
/*
	在JDK 1.6中的运行结果是:
------------------------
排序前数组data中的内容是:
1       3       5       7       2       4       6       8       10      9

排序后数组data中的内容是:
1       2       3       4       5       6       7       8       9       10
------------------------
*/
for(元素类型t 元素变量x : 遍历对象obj)
这种有冒号的for循环叫做foreach循环,foreach语句是java5的新特征之一,在遍历数组、集合方面,foreach为开发人员提供了极大的方便。
foreach语句是for语句的特殊简化版本,但是foreach语句并不能完全取代for语句,然而,任何的foreach语句都可以改写为for语句版本。
foreach并不是一个关键字,习惯上将这种特殊的for语句格式称之为“foreach”语句。从英文字面意思理解foreach也就是“for 每一个”的意思。实际上也就是这个意思。

foreach的语句格式:
for(元素类型t 元素变量x : 遍历对象obj){
引用了x的java语句;
}
示例代码:
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
for (String x : list) {
System.out.println(x);
}
Object s[] = list.toArray();
for (Object x : s) {
System.out.println(x.toString()); //逐个输出数组元素的值
}

这种写法是增强for循环,
for(int i = 0;i < s.length(); i++){
String str = s[i]; //当成数组的写法
}
编译器会认为:
1.创建名称为str 的String变量。
2.将s的第一个元素赋给str 。
3.执行重复的内容。
4.赋值给下一个元素str 。
5.重复执行至所有的元素都被运行为止
优点:
这种写法让我们代码看起来更加的简洁
缺点话:

只能顺次遍历所有元素,无法实现较为复杂的循环
2对于数组,不能方便的访问下标值;
3对于集合,与使用Interator相比,不能方便的删除集合中的内容(在内部也是调用Interator.
4 除了简单遍历并读取其中的内容外,不建议使用增强的for循环
java 1.5 以后的新特性,也叫foreach 语法。可以非常方便的遍历集合,数组。
很容易理解,for (String str : s){}for的条件中,String str前面的是new出来的临时变量,生存周期仅在本次循环中,这个变量的值是 集合 “S” 第N次循环第N个位置的元素(访问序号为N-1)。
可以看成这样的:
String[] s =; s是一个已存在的字符串数组
forint i = 0; i < s.length; i ++{
String str = s[i];
//下面是操作
}

相当于调用迭代器 Iterator 遍历的简单写法 ,是一个加强型的FOR循环操作,…
for(集合对象类型 代理对象名:集合名){ }

面向对象

1>封装

1.把一类事物静态属性和动态可以执行的操作组合在一起所得的这个概念就是类
2.类是抽象的,用来模拟一类事物,是一个概念
3.一旦定义了,类的概念就永远存在
4.定义:
    class Person
    {
        int age;
        void shout()
        {
        System.out.println("oh,my god!"+ age);
        }
    }
    1>age是类的属性,也叫类的成员变量,也叫字段,也叫域
    2>shout是类的方法,也叫类的成员函数
    3>shout方法可以直接访问同一个类中的age变量
5.访问与引用
    1>对象名.属性//访问对象的属性
    2>对象名.成员方法名()//访问对象的方法
    3>aa.i和aa.j叫做属性引用
    4>访问对象的属性和方法叫做引用
    5>对象引用较为特殊
        A aa  = new A();其中aa叫做类A引用类型的变量,存放在栈中,
        用来指向new出来的对象的“对象引用”

对象

1.类的一个个体
2.具体的,实实在在存在的事物
3.生命周期是短暂的,会生成和消亡

类与 对象

程序执行过程

访问控制符

1. 需要将类的属性变成私有的,外部类不能直接访问,希望把若干个
    方法变成一个个"按钮"提供给使用者,此时就需要访问控制符。
2.访问控制符有四种:
    public
    private
    protected
    默认【不写】
3.注意:
在一个类的内部,所有的成员可以相互访问,访问控制符是透明的
在一个类的外部:
			通过【类对象名.私有成员名】//error
             的方式是无法访问该对象中的私有成员的,
             这样写编译时会出错!

构造方法

1.特点:
不能有返回值 
方法名与类名相同 
可以有多个
2.注意:
    默认生成无参无方法体无返回值的构造函数
    自己一旦定义,编译器将不再生成默认的构造函数
    生成一个类对象时能且只能调用其中一个构造函数

初始化

1.当一个对象被创建会对其中各种成员变量自动进行初始化赋值
成员变量类型初始值
byte0
short0
int0
long0L
float0.0F
double0.0D
char‘\u0000’(表示为空)
booleanFlase
All reference typeNull
2.局部变量:
    1>方法中的形参
    2>方法内部变量
    3>main中的变量
3.
    1>如果在定义的时候不初始化,则它的值是系统自动分配好的
        默认值!
    2>如果在定义的同时赋初值,则是可以的,也就是说该值是生
        效的。注意在C++中则不可以,在C++中一个类的数据成
    	员不能在定义的同时初始化,它只能在构造函数中初始
    	化 如果在定义的同时赋初值,当然生效,但如果在构造
    	函数中又改变了定义时赋的初值,则该数据成员最终的
    	值就是构造函数中修改之后的那个值,
    	因为:
    	/*系统会先执行定义时赋的初值,然后再执行构
        造函数中赋的初值*/
            
4.	局部变量未初始化,其内部是垃圾值,Java要求局部变量在
    使用前必须初始化
    

Static

1.凡是Static修饰的成员都是静态成员
2.静态成员都是属于类的
	1>类的对象共用一个static属性或方法
    2>没有对象也可以通过类名的方式访问类
    	的内部static成员
  	  

3.
    非静态可以访问静态
    静态不可以访问非静态

4. 通过类名只能访问一个类中的非私有静态成员
   私有静态成员也不可以通过对象名访问

this

非静态方法默认都含有一个this指针
this代表正在调用本方法的对象

final

修饰类
    该类不能被继承
修饰方法
    该方法可以被继承但不能被重写
修饰属性
    表示该属性能且只能赋值一次,并只能选两种中一种赋值
        1.定义的同时显式的初始化
        2.构造方法中初始化



函数重载

函数重载:【方法名可以相同】(注:与C语言不同)
//以下示例省略方法体

	1同名不同参
		参数的
			  1>个数不同
			  	test(int i)
			  	test(int i,int j)
			  	
			  2>数据类型不同
			  	test(String str ,int i)
			  	test(int k,int i)
			  	
			  3>在数据类型不同的前提下,顺序不同 
	  			test(String str ,int i)
	  			test(int i,String str )
	  			
	  			
	  			
	2返回值不能作为是否构成重载的依据
			 	void test(int i)
				int  test(int i)
				×错误,不构成函数重载



	3访问控制符也不能作为是否构成重载的依据
				protected void  test(int i)
				public    void  test(int i)
				×错误,不构成函数重载

2>继承

定义

extends
子类继承了父类成员


1.概念:
    特殊类的对象具有一般类的对象的属性和行为,
    称特殊类对一般类的继承【子类对父类的继承】

2.动物与狗:
    狗继承了动物的属性与行为,
    而不是动物继承了狗的特征。

3.子类:关注子类与父类不同的特征:
       子类根据需求增加自己的新的属性和行为
	   父类与子类是相对而言的
       构造方法不能被继承

4.继承的优点:
    1.可实现代码重复使用,设计应用程序变得简单

5.结构:
    class son extends father
    {
        /*单继承,即一下写法
        错误:
        class son extends father ,mon{}
        
        但可以使用接口弥补单继承的缺陷
        */
    }

6.所有的类默认继承Object

权限

访问说明符/不同情况publicprotecteddefaultprivate
同包同类
访问同包不同类
同包不同类继承
不同包继承
访问不同包无任何关系的类

子类访问父类成员的三种方式

1.在子类内部访问父类成员
2.通过子类对象名访问父类成员
3.通过子类类名访问父类成员

内存

私有”成员物理上已经被继承过来,
只不过逻辑上程序员不能去访问它,
因此继承必须谨慎,否则会造成内存浪费

注意事项

非私有成员才可以被子类继承
重写:
    重写方法必须和被重写方法具有相同的方法名、参数列表、返回值类型
    重写方法的访问权限不能小于被重写方法

java只支持单继承

3>多态

定义

1.定义:同一代码可以随上下文的不同而执行不同的操作,俗称多态
即:
    一个父类的引用它既可以指向父类对象也可以指向子类对象
    它可以根据当前时刻指向的不同,自动调用不同对象的方法
2.注意事项:
    通过父类的引用只能访问子类从父类继承的成员
    只有父类的引用本身指向一个子类对象时,
    我们才可以把父类的引用强制转化为子类的引用

重写

规则:
    1.子类与父类中方法的方法头相同【方法名、返回值、形参】
    2.重写中:子类方法的访问权限不高于父类
    		private 最高
    		public  最低
   
重写范围 
    1> final  修饰的方法不能被重写
    2> static 修饰的方法不能被重写,但可以重新声明  ☆此处有疑问?
    3>
    	同包  :除 privatefinal 的方法
    	不同包:子类只能重写父类声明为 public protected 及 非 final 方法
    
    4>异常:
    

代码

package 笔记;


class A{
	
	void k() {
		System.out.println("父类方法被调用 ");
	}
	void f() {
		System.out.println("hello A");
		
	}
}

class B extends A{
	
	//f()
	public void f() {
		System.out.println("hello B");

	}
	
	void g() {
		System.out.println("这是g方法");

	}
	void k() {
		System.out.println("子类方法被调用 ");
	}
	//子类重写的范围大于父类
	
	
}

public class 重写 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

/*
		A a = new A();//父类的引用指向父类
		a.f();// "hello A"


		/*
		只有父类的引用本身指向子类才可以将其强制转换成子类的引用
		B b = (B)a; //error		
		 a = new B();//父类的引用指向子类
		 a.f();     //"hello B"
		 
		 
		 B b = (B)a;
		 
		 b.f();//"hello B"
		 
*/

		 A aa = new A();
		 B bb = new B();
		 
/*1.父类 ->子类->子类 	 转化过程
		 aa.f();//"hello A"
		 aa = bb;//子类直接给父类没问题
		 aa.f();//"hello B"
		 bb  =(B)aa;
		 bb.f();//"hello B"
		
		 
*/
		 
/*2.父类 ->子类 
		 aa.f();//"hello A"
		 aa = (A)bb;
		 aa.f();//"hello B"
		 
*/
		 
		 
/*3.子类->父类 
		// bb = aa;//error
	 
		 bb = (B)aa;//error

*/		 

		 
/*
/4.子类转成父类
  子类中的方法不是特有的,优先调用子类的
		 aa = bb;
		 
		 A a2 = (A)aa;
		 
		 a2.f();
*/		 
		 
/*
 指向子类的父类引用 -> 父类转 :随意

指向子类的父类引用 -> 子类转   :强转

子类->父类    :随意
父类->子类    ×


*/
    

		 
/*		 a.g(); error 只能访问从父类继承的成员【成员属性和成员方法】
		 				子类特有成员不能被访问

*/

		
	}

}

4>相关知识

抽象类

1.抽象类 [可见度 abstract class A] 
       1>不可以实例化抽象类对象,但抽象类可以实现多态
       2>一个抽象类"通常"都含有抽象方法
       3>只重写抽象类部分抽象方法的类也必须标记为 abstract
       4>有一个抽象方法就必须是抽象类
       4>抽象类可以有构造方法
    
    总结:除了无法实例化对象外,与普通类无异
       
 2.抽象方法  
   public  abstract int fangfa(int i);//注意:没有花括号

接口

1.格式:
        "现有:
            "类: MM , NN
            "接口 QQ, VV, KK, LL

        1>接口:
                //1.基本格式
                    [可见度] interface 接口名称
                    {
                         int a = 0;//等效与 public   static  final int a = 0;
                         void f(); //等效与 public   abstract void f();
                    }


                //2.接口只能继承接口,并且允许多继承
                interface A3 extends QQ,VV{  
                }

        2>类:
                //3.类可以继承类,实现接口
                class  A1 extends NN implements VV,QQ{
                /*
                 * 类:
                 * 1.只能继承一个类
                 * 2.接口可以多个
                 */

         3>总结:"接口只能继承接口,并且允许多继承
                "类可以继承类,实现接口
2.注意事项:
接口
继承接口√ [此处代表接口继承接口]× [此处代表类继承接口]
实现接口×
继承类×
实现类××
3."抽象类:
    1.抽象类同上表格
	{
    	并且:
    	1> "抽象类可实现接口
            并且可以不实现接口中的方法,但是继承
           抽象类的实体类必须实现接口中的方法。
       	2> "抽象类可以继承实体类
            但前提是实体类必须有明确的构造函数
            原因:抽象类有方法,也具备继承性
	}
 4.定义:
    1.接口是抽象类型,也是抽象方法的集合,但不是类
    2.注意事项:
        "方法:
            1>接口没有构造方法
            2>接口中的所有方法必须是抽象方法,且必须是 public  
    			即:接口中方法都是 
                        "  public abstract " 
                        例如: public abstract void f();

    	    3>不可以定义接口对象,但接口可以实现多态
                    可以实例化一个继承了抽象类的子类,
                    然后将抽象类的引用指向子类的对象。
            
		    4>重写接口方法时, public 不能省
                	   /*【原因】
                        接口中方法默认是  public abstract 
                        子类在重写时父接口时,
                        由于子类方法访问权限不高于父接口方法,
                            {
                                即子类方法范围>=父接口方法范围
                                比如: public > 默认
                            }
                        父接口中方法范围已经是最大【 public 】
                        子类方法范围不能在小,即 public 不可省略*/


                
        "属性:
    		1>接口不能包含成员属性,除了 public static  final 变量
     			即:接口中属性都是 
                        " public static final " 
                        例如: public static final int a = 0 ;

                        /*【原因】
                        接口中属性默认是  public static final 
                        由final修饰的属性只能赋一次值,
                        且只能是在定义时显示赋值
                        或构造方法赋值,又由于接口中没有构造方法,所以
                        只能在定义时显示赋值*/


 5.接口支持多重继承
    	书写时:先继承在实现["顺序不能错"]
    	 [可见度] class 类名 extends MM implements KK,LL{
		 }
    
   
 6.举例:
        线程创建
        GUI事件处理
        容器的组织方式
        serializable接口



高级部分

1>异常

什么是异常

异常(Exception)是程序运行过程中发生的事件,该事件可以中断程序指
令的正常执行流程。

为什么需要异常

异常的处理机制

异常的处理机制(重点)
    1.Java程序运行时出现问题时,系统会自动检测到该错误
       并立即生成一个与该错误对应的异常对象
    2. 然后把该异常对象提交给Java虚拟机
    3. Java虚拟机会自动寻找相应的处理代码来处理这个异常,
       如果没有找到,则程序终止!
    4. 程序员可以自己编写代码来捕捉可能出现的异常,并编写代
       码来处理相应的异常

常见的异常

空指针异常
下标越界异常
算数异常

异常的分类

Throwable
Error 
Exception
RuntimException
异常的分类
1.Error:Java虚拟机生成并抛出,包括动态链接失败、虚拟机错误等,Java
        程序无法对此错误进行处理。
2.RuntimeException:	
        Java虚拟机在运行时生成的异常,如被0除等系统错误、数组下标超
        范围等,其产生比较频繁,处理麻烦,对程序可读性和运行效率影响
        太大。因此由系统检测,用户可不做处理,系统将它们交给缺省的异
        常处理程序(当然,必要时,用户可对其处理)3.Exception:
        一般程序中可预知的问题,其产生的异常可能会带来意想不到的结果
        因此Java编译器要求Java程序必须捕获或声明所有的非运行时异常
4.处理
        error是系统的错误,程序员无法处理这些异常
        Exception是程序员可以捕获并处理的异常。
        RuntimeException的子类异常,是可以处理也可以不处理的异常
        凡是继承自Exception但又不是RuntimeException子类的异常必须捕捉并处理

异常的处理步骤

try 
{
    可能出现异常的代码快
}
catchExceptioName1 e)
{
    当产生ExceptionName1 异常时的处理措施
}
catchExceptioName2 e)
{
    当产生ExceptionName2 异常时的处理措施
}
......
finally
{
    无论是否捕捉到异常都必须处理的代码
}

Finally
    1. 无论try所指定的程序块中是否抛出异常,也无论catch语句的异常类型是否与所抛弃的异常的类型一致,
       finally中的代码一定会得到执行
    2. finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序的
       状态作统一的管理
    3. 通常在finally语句中可以进行资源的清除工作。如关闭打开的文件,删除临时文件
throw
1.throw用来抛出异常
2.格式:
    throw new 异常名(参数)//从本质上来说这是 new出一个类对象,以及调用构造函数
3.假设f方法抛出了A异常,则f方法有两种方式来处理A异常
    1>throws A
        谁调用f方法,谁处理A异常,f方法本身不处理A异常
    2>try{···}catch{···}
        f方法本身自己来处理A异常
4.要抛出的异常,必须是Throwable的子类
  

throws
1.格式:
void f() throws A
{
    ······
    ······
}

2.thows A表示调用f方法时f方法可能会抛出A类异常,建议您调用f方法时
最好对f方法可能抛出的A类异常进行捕捉
3.throws A不表示f方法一定会抛出A类异常
4.throws A,f方法也可以不抛出A类异常
5.throws A不表示调用f方法时,必须的对A异常进行捕捉
    1> 假设ARuntimeException子类异常
    2> 由于RuntimeException的子类异常可以处理也可以不处理,所以编译器允
       许你调用f方法时,对f方法抛出的RuntimeException子类异常不进行处理

 6.强烈建议:
 1.对 thorws出的所有异常进行处理
 2.如果一个方法内部已经对A异常进行了处理,就不要再throws A
异常的两种处理方法

自定义异常

参见代码

异常的优缺点

优点:
    1. 强制程序员考虑程序的安全性与健壮性
    2. 增强了程序员对程序的可控性(处理完错误程序可以继续运行)
    3. 有利于代码的调试
    4. 把错误处理代码从常规代码中分离出来

缺点:
    1. 异常并不一定能够使程序的逻辑更清晰
        因为有时我们必须得编写代码捕捉异常,所以可能会导致程序的逻辑非常混乱

    2. 异常并不能解决所有的问题

异常的注意事项

1. 异常的范围
    子类覆盖了基类方法时,
        子类方法抛出异常的范围不能大于基类方法抛出的异常范围
        子类方法可以不抛出异常,也可以只抛出基类方法的部分异常
        但不可以抛出基类方法以外的异常
2.catch子类异常再catch父类异常
	如果先catch父类异常再catch子类异常,则编译时会报错
3. 所有的catch只能有一个被执行
4. 有可能所有的catch都没有执行
5. catchcatch之间不能有其他代码

2>线程

程序

1.程序: 
    是一个严格有序的指令集合。程序规定了完成某一任务时,计算机所需做的各种操作,以及这些操作的执行。

2.单道程序设计环境:
    1>计算机中除了操作系统之外,只存在一个用户程序,即用户程序独占整个计算机资源。
    2>特点:
        资源的独占性
        执行的顺序性
        结果的再现性
3.多道程序设计环境:
    1>计算机中除了操作系统之外,存在多个用户程序,这些程序同时运行
    2>特点:
        间断性:由于资源共享合作,并发程序相互制约,造成合作执行间断
        失去封闭性:程序首外界影响
        结果不可再现性

线程的概念

进程
1. 进程的由来
     为了不破坏“程序”这个词原有的含义,而又能刻画多个程序共同
     运行是呈现出的新特征,所以引入了进程的概念
2.进程:
    是一个动态的实体,是程序在某个数据集上的执行。它有自己的生命体,
    它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因
    完成任务而被撤销
3.举例:
    一个记事本程序同时打开三个文本,则产生了三个进程
4.我的理解:
    由于程序与程序运行之间不再是一一对应的关系,需要创造一个新的词语来描述他们之间的关系,这就是进程
5.进程的缺点:
    浪费时间与资源,因此创建了线程
线程
1.定义:
    一个程序运行时的不同执行路径
2.多线程的优势
    1>多线程编程简单,效率高 (能直接共享数据和资源,多进程不能)
    2>适合于开发服务程序 如 (Web服务,聊天服务等)

如何创建一个线程

方法一:继承Thread
1.步骤:
    1>创建一个继承Thread的类(假定类名为A),并重写Thread中的run方法
    2>构建一个A类对象,假定对象名为aa
    3>调用aa的start方法
2.注意问题:
    1> Threadstart()方法的功能就是创建一个新的线程,并自动
      调用该线程的 run()方法,直接调用 run()方法是不会创建一个
      新的线程的
 
    2>执行一个线程实际就是执行该线程run方法中的代码
     执行完aa.start();后并不表示aa所对应的线程就一定会立即得
     到了执行,aa.start();执行完后只是表示aa线程具有了可以
     立即被CPU执行的资格,但由于想抢占CPU执行的线程很多
     CPU并不一定会立即去执行aa所对应的线程
     参见TestThreadStart.java

    3>一个Thread对象能且只能代表一个线程,
     一个 Thread对象不能调用两次 start()方法,否则会抛出
     java.lang.lllegalThreadStateException异常
     参见TestThreadStart2.java
3.代码:
一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例
class A extends Thread
{
	public void run()
	{
		while (true)
		{
			System.out.println("AAAA");
		}			
	}
	
}

public class TestThread_1
{
	public static void main(String[] args)
	{
		A aa = new A();
		aa.start(); //aa.start(); 会自动调用run方法
		while (true)
		{
			System.out.println("BBBB");
		}
	}
}

方法二:实现了Runnable接口
1.步骤:
    1>定义一个实现了Runnable接口的类,假定为A
    2>创建A类对象aa,代码如下
         A aa=newA();
    3>利用aa构造一个Thread对象t,
        Thread tt = new Thread(aa);
    4>调用t中 的start方法
         tt.start(); 

2.代码:
一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时
作为一个参数来传递并启动。
        class A implements Runnable
        {
            public void run()
            {
                while (true)
                {
                    System.out.println("AAAA\n");
                }
            }
        }



        public class TestThread_2
        {
            public static void main(String[] args)
            {
                A aa = new A();
                //aa.start();  //error
                Thread t = new Thread(aa); public Thread(Runnbale r) 

                t.start();
                
                while (true)
                {
                    System.out.println("BBBB\n");
                }
            }
        }


class TT extends Thread
{
	public void run()
	{
		while (true)
		
			System.out.println("继承Thread类的线程执行!!\n");
			
	}
	
}


class Ra implements Runnable
{
        public void run()
        {
        	while(true)
                System.out.println("实现Runnable接口的线程执行!!\n");
        
    }
}


public class Punnable_2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

			TT th1 = new TT ();
			th1.setPriority(TT.NORM_PRIORITY+5);
		
			Ra ra = new Ra();
			Thread th = new Thread (ra);
			
			System.out.printf("th1 :%s\n",th1.getPriority());
			System.out.printf("th :%s \n",th.getPriority());
			
			th1.start();
			th.start();
			
			
			
	}

}


推测Thread 内部代码
public interface Runnable
{
    public void run()
    {
        如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否			
         则,该方法不执行任何操作并返回。
    }

}

public class Thread extends Object implements Runnable
{
    Runnable target = null;
    public Thread{
    	}
    public Thread(Runnable target){
       this.target = target;
    }
	void start() {
          使该线程开始执行;Java 虚拟机调用该线程的 run 方法} 
	 public void run() {
        if (target != null) 
            target.run();
        }
}

--------------------------------------------------------------------------------------------------------------

API:
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。 

设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread 类实现了 Runnable。激活的意思是说某个线程已启动并且尚未停止。 

此外,Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个 Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。

CSDN:
不论是继承Tread类创建线程还是实现Runnable接口创建线程,启动线程一般都是调用Thread类的start()方法,然后由虚拟机自动调用Thread类的run()方法
综合上述五种情况分析:
1.如果没有继承Thread类只是创建普通Thread类对象,则线程什么都不做
2.如果继承了Thread类:
    a.如果重写了run()方法:则JVM调用该方法
    b.如果没有重写run()方法:则JVM调用JDK自己定义的run()方法
         I.如果指定了target,则调用target的run()方法
         II.如果没有指定target,则什么都不做。

Thread 的常用方法
1.格式:
    public final void setName(String name)设置当前线程的名字
    public static Thread currentThread()返回对当前正在执行的线程对象的引用
    public final String  getName();返回当前线程的名字

2.使用:
    Thread.setName(String name)
		设置当前线程的名字
	Thread.currentThread()
		返回当前线程的引用
	Thread.getName()
		返回当前线程的名字
3.代码:

class A extends Thread
{
	public void run()
	{
		//System.out.println("AAAA");
		System.out.printf("%s在执行!\n", Thread.currentThread().getName());
	}                       //currentThread()方法是静态的,此处使用类名.方法调用
}

public class TestThread_3
{
	public static void main(String[] args)
	{
		A aa1 = new A();
		aa1.setName("张三");
		aa1.start();
		
		A aa2 = new A();
		aa2.start();
		
		A aa3 = new A();
		aa3.setName("李四");
		aa3.start();
		
		//System.out.println("BBBB");
		System.out.printf("%s在执行!\n", Thread.currentThread().getName());
	}
}

线程的控制

线程控制的基本方法
方法功能
isAlive ( )判断线程是否还"活"着,即线程是否还未终止
getPriority( )获得线程的优先级数值
setPriority( )设置线程的优先级数值
Thread. sleep ( )将当前线程睡眠指定亳秒数
join ( )调用某线程的该方法,将当前线程与该线程“合并,即等待该线程结束,再恢复当前线程的运行。
yield( )让出CPU,当前线程进入就绪队列等待调度。
wait ( )wait ()
当前线程进入对象的wait pool.
notify( ) / notifyAll ()唤醒对象的wait poo1中的一一个/所有等待线程
优先级控制
1.  Java提供-一个线程调度器来监控程序中启动后进入就绪状态的所有线程。
    线程调度器按照线程的优先级决定应调度哪个线程来执行。

2.  线程的优先级用 数字表示,范围从110, 一个线程的缺省优先级是51>Thread.MIN PRIORITY=1
        2>Thread.MAX_ PRIORITY= 10
        3>Thread.NORM PRIORITY= 5

3.  使用下述线方法获得或设置线程对象的优先级。
        1>int getPriority();
        2>void setPriority(int newPriority);

4. 通常高优先级的线程将先于优先级低的线程执行,但并不
   总是这样,因此实际开发中并不单纯依赖优先级来决定线
   程运行次序  

5.代码:TestPriority.java
            Thread t1 = new Thread(new T1());
            Thread t2 = new Thread(new T2());
            t1.setPriority(Thread.NORM_PRIORITY + 3); 
            t1.start();
            t2.start();
            t1 优先级比 t2 高,执行完t1再执行t2 //考虑把本语句注释掉后会怎样
/*
详见源码
t1 与t2 交替执行;
*/

时间片轮转

线程的休眠、让步、挂起和恢复
休眠
1.  线程休眠一暂 停执行当前运行中的线程,使之进入阻塞状
    态,待经过指定的“延迟时间”后再醒来并转入到就绪状态。

2.  Thread类提供的相关方法:
        1> public static void sleep(long millis)
        2> public static void sleep(long millis, int nanos)

3.  由于是静态方法,可以由Thread直接调用

4. sleep()方法会抛出InterruptedException异常,我们必须得
        对其进行捕捉
        try{
	 	     Thread.sleep(1000); //行  这里的Thread.sleep(1000)会抛出异常,必须
                                      //的进行捕捉,不能在9 的后面添加 throws Exception
		}catch (Exception e){  }
	    

5. 注意问题:
        无论是继承Thread类的run方法还是实现 Runnable接口的run方法,都不能抛出任何异常,
        原因:重写方法抛出异常的范围不能大于被重写方法排除的异常范围 【TestSleep2. java】


	
让步
1.  让出CPU,给其他线程执行的机会

2.  让运行中的线程主动放弃当前获得的CPU处理机会,但不是
    使该线程阻塞,而是使之转入就绪状态。
        public static void yield()TestYield.ava】


挂起和恢复
1.  线程挂起一 暂时停止当前运行中的线程,使之转入阻塞状态,并且不会
    自动恢复运行。
2.  线程恢复一使得一个已挂起的线程恢复运行

3.  Thread类提供的相关方法:
        1> final void suspend()
        2> public final void resume()
        3> suspend()方法挂起线程时并不释放其锁定的资源。这可能会影响其他线
           程的运行,且容易导致线程的死锁,已不提倡使用
线程的串行化
1. 在多线程程序中,如果在一个线程运行的过程中要用到另一
   个线程的运行结果,则可进行线程的串型化处理。

2. public final void join() throws InterruptedExceptionTestJoin.java】

3.代码:
public class TestJoin {	
	public static void main(String args[]){
		MyRunner r = new MyRunner();
		Thread t = new Thread(r);
		t.start();
		try{
			t.join(); //7行  暂停当前正在执行t.join();的线程,直到t所对应的线程运行终止之后,当前线程才会获得继续执行的机会
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		for(int i=0;i<50;i++){
			System.out.println("主线程:" + i);
		}
    }
}

class MyRunner implements Runnable {
	public void run() {
		for(int i=0;i<50;i++) {
			System.out.println("子线程: " + i);
		}
	}
}

线程的生命期控制
如何结束一个线程
注意:此方法不一定可以起作用
public class TestShutThread
{
	public static void main(String[] args)
	{
		A aa = new A();
		Thread tt = new Thread(aa);
		tt.start();
		
		try
		{
			Thread.sleep(5000);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}		
		
		aa.shutDown();
	}	
}

class A implements Runnable
{
	private boolean flag = true;
	
	public void run()
	{
		while (flag)
		{
			System.out.println("AAAA");
			  
		}
	}
	
	public void shutDown()
	{
		this.flag = false;
	}
}

zzJuJJJ

线程同步

线程同步知识点
同步概念
1.定义:
	通常,一些同时运行的线程需要共享数据。在这种时
	候,每个线程就必须要考虑与其他-起共享数据的线程的
	状态与行为,否则的话就不能保证共享数据的一-致性,从
	而也就不能保证程序的正确性

2.不同步带来的问题:
	当有两个线程AB同时使用了Stack类的-一个对象时,现在我要求:先把r存
	入Stack中,再将r取出来
	下面的步骤详细演示了AB线程不同步所带来的问题
		1>操作之前,堆栈中有两个字符:
			data=|a |c |  |  |  |  index= 2
		2>A执行push中的第一条 语句data[index]='r':
			data=|a |c |r |  |  | 	index= 2		//2还没有被存入

		3> A还没有执行index++语句,AB中断,B执行pop()方法, 返回'c':
			data=|a |c |r |  |  |	index = 1	//取出的是'C'却不是‘r'
	
		4>A继续执行index++语句:
			data=|a |c |r |  |  |		index = 2
			■最终结果是: 'r'没有被存入,取出的是'C'而不是'r


Synchronized关键字
1.synchronized可以用来修饰.
    一个方法
    一个方法内部的某个代码块

2.Synchronized修饰方法
    1>  Synchronized修饰一个方法时,实际霸占的是该方法的this
        指针所指向的对象,Synchronized修饰一一个方法时,实际
        霸占的正在调用该方法的对象
    2>附注:
        霸占的专业术语叫锁定,霸占住的那个对象专业术语叫做监听器



3.Synchronized修饰代码块
    1>格式:
            synchronized(类对象名aa) I/1{
                同步代码块//3行
                } //4行

    2>功能:
        synchronized(类对 象名aa)的含义是:判断aa是否已经被其他线程
        霸占,如果发现已经被其他线程霸占,则当前线程陷入等待中,如果
        发现aa没有被其他线程霸占,则当前线程霸占住aa对象,并执行3行
        的同步代码块,在当前线程执行3行代码时,其他线程将无法再执行3
        行的代码(因为当前线程已经霸占了aa对象),当前线程执行完3行的代
        码后,会自动释放对aa对象的霸占,此时其他线程会相互竞争对aa的
        霸占,最终CPU会选择其中的某一个线程执行

    3> 最终导致的结果是:
        一个线程正在操作某资源的时候,将不允许其它线程操作该资源,即一次
        只允许一个线程处理该资源
notify 和 wait
1.格式:
	this.notify();
2.功能:
	1> 不是叫醒正在执行this.notify();的当前线程
	2> 而是叫醒一个现在正在wait this对象的其他线程,如果有多个线程正
	   在wait this对象,
	3> 通常是叫醒最先waitthis对象的线程,但具体是叫醒哪一个这是由系统调
	   度器控制,程序员无法控制
3.分析:
	假设现在有T1、T2、T3、T4 四个线程
	我们在T4线程中执行了aa.notify()语句
	则即便此时 T1 T2 T3 没有 一个线程因为wait aa对象而陷入阻
	塞状态,T4线程中执行aa.notify方法时也不会有任何错误
	本程序就证明了这一点
	执行aa.notify方法时如果一个线程都没有叫醒,这是可以的
									【TestNotify.java】
									【SyncTest.java  】
4.总结:
	1>aa.wait()
		将执行aa. wait()的当前线程转入阻塞状态,让出CPU的控制权
		释放对aa的锁定
	2>aa.notify()
		假设执行aa. notify()的当前线程为T1
		如果当前时刻有其他线程因为执行了aa.wait()而陷入阻塞状态,则叫醒其中的一个,
		所谓叫醒某个线程就是令该线程从因为wai而陷入阻塞的状态转入就绪状态
	3>a.notifyAll()
		叫醒其他所有的因为执行了aa.wait()而陷入阻塞状态的线程


5.



6.代码:
public class SyncStack
{
	private int index = 0;
	private char []data = new char[6];
	public synchronized void push(char c)
	{
		while(index == data.length)
		{
			try{
				this. wait(); //7行
				}
			catch(InterruptedException e){}
		}
			this.notify(); //10行
			data[index]=c;
			index++;
			System.out.println("produced: "+c);
	}
}

public synchronized char pop()
{
	while(index ==0)
	{
		try{
			this. wait();
			}
		catch(Exception e){}
	}
	this.notify(); //20行
	index--;
	System.out.println("消费: "+data[index]);
	return data[index]; //23行
}
/*
1.要注意的问题
	1>执行完20行的代码后,程序绝对不会立即切换到另一个线程
	2>0行代码叫醒的是其他线程,叫醒的不是本线程
	3>在最开始,P和C刚开始执行时,即便P没有wait,也可以在C中
	notify,即便C没有wait,也可以在P中notify

 2.解释说明:
	假设现在有两个线程P(生产)和C(消费),
	P生产已满,执行7行代码陷入阻塞状态,同时释放P
	线程对this的锁定,这时候C线程会得到this对象的标
	志位开始运行。另外C线程执行完20行代码后,程序并
	不会立即转到P线程开始运行,因为C执行notify,只是
	叫醒P,让P从因为wait this对象而陷入阻塞的状态进
	入就绪状态,
	记住:一个线程notify,该线程并不会释放对this的锁
	定,只有C执行完23行的代码后,C才会释放对this的
	锁定,这时候C和P会同时争夺对this的锁定,具体执
	行哪个由系统调度器决定
*/


线程同步案例
买票

1.买票程序
    if (票数>0)
    {
        买一张票;
        票数减一;
    }

2> "继承Thread" 方法买票
class A extends Thread
{
	public static int tickets = 1000;  //static不能省
	public static String str = new String("哈哈");  //static不能省
		
	public void run()
	{
		while (true)
		{
			synchronized (str)
			{
				if (tickets > 0)
				{
					System.out.printf("%s线程正在卖出第%d张票\n",
						Thread.currentThread().getName(), tickets);
					--tickets;	
				}
				else
				{
					break;
				}
			}
		}
	}
}

public class Q21
{
	public static void main(String[] args)
	{
		A aa1 = new A();
		aa1.start();	
			
		A aa2 = new A();
		aa2.start();		
	}
}

3> "实现Runnable接口"方法买票
class A implements Runnable
{
	public int tickets = 1000;//计算机运行较快,次数多,结果明显
	String str = new String("哈哈");
		
	public void run()  
	{
		String str = "哈哈";  
		
		while (true)
		{
			synchronized (str)  
			{
				if (tickets > 0)
				{
					System.out.printf("%s线程正在卖出第%d张票\n",
						Thread.currentThread().getName(), tickets);
					--tickets;	
				}
				else
				{
					break;
				}
			}
		}		
	}
}

public class TestTickets_9
{
	public static void main(String[] args)
	{
		A aa = new A();
		Thread t1 = new Thread(aa);
		t1.start();	
		
		Thread t2 = new Thread(aa);
		t2.start();	
			
	}
}

生产和消费问题
生产消费[经典问题]
■一个仓库最多容纳25个产品,制造商现在要制造50件产品存入
仓库,消费者要从仓库取出这50件产品来消费
■
制造商制造产品和消费者取出产品的速度很可能是不一样的
编程实现两者的同步  【ProducerConsumer.java】



package com.ghy.a2;
//仓库
class Warehouse
{
	private char house [] = new char [25];
	private int cnt = 0;
	
	//生产
	public synchronized  void push(char ch)
	{
		if(cnt==house.length) 
		{
			try
			{
				this.wait();
			}
			catch (Exception e)
			{
			}
			
		}
		this.notify();	
		house [cnt] = ch;
		System.out.printf("生产第%d个商品%c\n",cnt+1,ch);
		cnt++;
	}

	//消费
	public synchronized  void pop()
	{
		if(cnt==0)
		{
			try
			{
				this.wait();
			}
			catch (Exception e)
			{
			}
		}
		this.notify();
		System.out.printf("消费第%d个商品%c\n",cnt,house [cnt-1]);
		cnt--;
	}
	
}

//生产
class Production implements Runnable
{
	Warehouse w = null;
	Production (Warehouse w){this.w = w;}
	
	public void run()
	{	int i;
		char ch = 'a';
		for(i=0;i<50;++i)
		{
			ch = (char)('a'+i);
			w.push(ch);
		}
		
		
	}

}

//消费
class Consumption implements Runnable
{
	Warehouse w = null;
	Consumption (Warehouse w){this.w = w;}
	
	public void run()
	{
		 int i;
		 for(i=0;i<50;++i)
		 {
				// try{
					// Thread.sleep(100);
					//}
				//catch (Exception e){}	
				 w.pop();
		 }
		
	}
	
}


public class 生产与消费 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Warehouse   ww = new Warehouse();
		Production  pr = new Production (ww);
		Consumption co = new Consumption(ww);
		
		Thread p = new Thread (pr);
		Thread c = new Thread (co);
		p.setName("生产线 ");
		c.setName("消费线");
		p.start();
		c.start();
		
	}

}

3>包

4>GUI

组件与容器

1.	组件(Component)是图形用户界面的基本组成元素,凡是能
	够以图形化方式显示在屏幕上并能够与用户进行交互的对象
	均为组件,如菜单、按钮、标签、文本框、滚动条等。
2.组件分类   
		1>java.awt.Component 
		2>Java.awt.MenuComponent
		3>说明:抽象类java.awt.Component是除菜单相关组件之外所有Java
		  AWT组件类的根父类,该类规定了GUI组件的基本特性,如尺寸、位
		  置和颜色效果等,并实现了作为一个GUl部件所应具备的基本功能
3.容器:
		1>组件通常不能独立地显示出来,必须将组件放在一定的容器中才可以显示出来。
		2>有一类特殊的组件是专门用来包含其他组件的,这类组件叫做容器,
			java.awt.Container是 所有容器的父类,java.awt.Container
			继承自 java.awt.Component  
		3>容器类对象本身也是一个组件,具有组件的所有性质,但反
		  过来组件却不一定是容器

4.Frame常用的方法  


		1>public void setBounds(int x,int y,int width, int height)
			设置窗体的位置和大小,x和y表示窗体左上角距离屏幕的水平和垂直
			距离,with和height是 窗体本身的宽度和高度
		2>public void setSize(int width, int height)
			设置窗体的大小,with和height是窗体本身的宽度和高度
		3>public void setVisible(boolean flag);
			设置窗体是否可见,true表示可见,false表示不可见
		4>public void setBackground(Color c)
			设置窗体的背景色
									TestFrame_ 1.java
									TestFrame_ 2.java
									TestFrame_ 3.java

									

5.Panel
		1>panel是容纳其他组件的组件
		2>panel是容器
		3>panel不能单独存在,必须得被添加到其他容器中
			Panel类拥有从其父类继承来的
				setBounds(int x,int y,int width,int height)
				setSize(int width, int height)
				setLocation(int x,int y)
				setBackground(Color c)
				setLayout(LayoutManager mgr)等方法。
				Panel的构造方法为:
				Panel()使用默认的FlowLayout类布局管理器初始化
				Panel(LayoutManager layout)使用指定的布局管理器初始化
										【TestPanel 1.java】

6.注意:
		Frame f = new Frame("标题!"); 
		Panel p = new Panel ();
		//f与p都是容器,但f可单独显示出来,p不行

布局管理器

概念
1.	容器对其中所包含组件的排列方式,包括组件的位置和大小.
	设定,被称为容器的布局(Layout)

2.	为了使图形用户界面具有良好的平台无关性,Java语言提供
	了布局管理器来管理容器的布局,而不建议直接设置组件在
	容器中的位置和尺寸

3.	每个容器都有一个默认的布局管理器,当容器需要对某个组
	件进行定位或判断其大小尺寸时,就会自动调用其对应的布
	局管理器

4.	在AWT中,常见的布局管理器:
	1> GridLayout	 BorderLayout	FlowLayout
        [网格布局]    [边界布局]       [流式布局]
	2> Frame 默认的布局管理器: BorderLayout (记忆:FBL )
	3> Panel 默认的布局管理器:	FlowLayout
FlowLayout布局管理器
1. FlowLayoutPanel类的默认布局管理器。
	1>FlowLayout布局管器对组件逐行定位,行内从左到右,一行排满后换行
	2>不改变组件的大小, 按组件原有尺寸显示组件,可设置不同的组件间距,
	  行距以及对齐方式

2.FlowLayout 布局管理器默认的对齐方式是居中。


3. 
	1>	new FlowLayout(FlowLayout.RIGHT,20,40);
			右对齐, 组件之间水平间距20个像素,垂直间距40个像素
	2>	new FlowLayout(FlowLayout.LEFT);
			左对齐, 水平和垂直间距为缺省值(5)
	3>	new FlowLayout();
			使用缺省 的居中对齐方式,水平和垂直间距为缺省值(5)TestFlowL ayout.java】
									【TestFlowI ayout2.java】

BorderLayout布局管理器
1.  BorderLayoutFrame类的默认布局管理器

2. BorderLayout将整个容器的布局划分成
	1>(EAST)
	2>西(WEST)
	3>(SOUTH)
	4>(NORTH)
	5>(CENTER) 五个区域,组件只能被添加到指定的区域

2. 如不指定 组件的加入部位,则默认加入到CENTER区
3. 每个区域只能加入一个组件, 如加入多个,则先前加入的会被覆盖。

4. BorderLayout型布局容器尺寸缩放原则: 
	1> 北、南两个区域在水平方向缩放
	2>东、西两个区域在垂直方向缩放
	3>中部可 在两个方向上缩放
									【GUl/TestBorderLayout. java】

GridLayout布局管理器
1.  GridLayout型布局管理器将空间划分成规则的矩形网格,每个单元格区
	域大小相等。组件被添加到每个单元格中,先从左到右添满一行后换
    行,再从上到下

2.GridLayout构造方法中指定分割的行数和列数:
	 GridLayout(3,4)


3.注意:
   GridLayout是 以行数为准的 //重点

布局管理器总结
1. Frame是一一个顶级窗口,Frame的默认布局管理器为BorderLayout

2. Panel无法单独显示,必须添加到某个容器中。
	Panel的缺省布局管理器为FlowL ayout。

3. 当把Panel作为一个组件添加到某个容器中后,该Panel仍然可以有自己
   的布局管理器

4. 使用布局管理器时,布局管理器负责各个组件的大小和位置,因此用户无
   法在这种情况下设置组件大小和位置属性,如果试图使用Java语言提供
   的 setLocation(),setSize(),setBounds()等方法, 则都会被布局管
   理器覆盖

5. 如果用户确实需要亲自设置组件大小或位置,则应取消该容器的布局管理
   器,方法为:
		setLayout(null)


十个按钮
import java.awt.*;

public class 十个按钮 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//十个按钮
		Button b1  =new  Button("1");
		Button b2  =new  Button("2");
		Button b3  =new  Button("3");
		Button b4  =new  Button("4");
		Button b5  =new  Button("5");
		Button b6  =new  Button("6");
		Button b7  =new  Button("7");
		Button b8  =new  Button("8");
		Button b9  =new  Button("9");
		Button b10 =new  Button("10");
		
		//整体
		Frame f = new Frame("十个按钮");
		f.setLayout(new GridLayout(2,1));
		
		//上面的
		Panel p1 = new Panel ();
		p1.setLayout(new BorderLayout());
		//上中
		Panel p1_1 = new Panel();
		p1_1.setLayout(new GridLayout(2,1));
	
		
		//组合上
		p1.add(b1, BorderLayout.WEST);
		p1_1.add(b3);
		p1_1.add(b4);
		p1.add(p1_1, BorderLayout.CENTER);
		p1.add(b2, BorderLayout.EAST);
		

		//下面的
		Panel p2 = new Panel ();
		p2.setLayout(new BorderLayout());
		
		//下中
		Panel p2_2 = new Panel();
		p2_2.setLayout(new GridLayout(2,2));

		//组合下
		p2.add(b5, BorderLayout.WEST);
		p2_2.add(b7);
		p2_2.add(b8);
		p2_2.add(b9);
		p2_2.add(b10);
		p2.add(p2_2);
		p2.add(b6, BorderLayout.EAST);
	
		f.add(p1);
		f.add(p2);
		f.setBounds(45, 45, 400, 400);
		f.pack();
		f.setVisible(true);
		
	
	}

}

事件处理

事件处理相关概念
1.事件处理相关概念:
	1>事件(Event)
		用户对组件的一个操作,称之为一一个事件
	2>事件源(Event Source)
		能够产生事件的GUl组件对象,如按钮、文本框等。
	3>事件处理方法(Event Handler)
		能够接收、解析和处理事件类对象,实现与用户交互功能的方法。
	4>事件监听器(Event Listener)
		可以处理事件的一一个类。

2.默认情况下事件源不会自动产生任何事件,程序员需要做两件事:
		1>告诉事件源可以自动产生哪类事件,即:向事件源注册某种事件的事
		件监听器对象

		2>设计好可以处理这种事件的事件监听器

		3>一旦完成了这两步操作,当用户对事件源进行操作时,事件
		源就会自动产生事件,事件源就会自动把产生的事件封装成
		一个事件对象,事件源就会自动把封装好的事件对象传递给
		事件监听器
		
		4>事件监听器收到事件源发送过来的事件时,事件监听器就会
		自动调用相应的事件处理方法来对该事件进行相应的处理



事件处理步骤
1. 假设事件为XXXX
	1>向事件源注册某种事件的事件监听器对象
		addXXXXListener.(...);
	2>设计好可 以处理这种事件的事件监听器
	   class类名implements XXXXListener

	{
		重写XXXXListener接口中的方法
	}

2.	要想设计出能够处理XXXX事件的监听器,只需要编写出实现了
	XXXXListener接口的类就OK了,因为XXXXListener接口中已经定义了
	可以处理XXXX事件的方法

3.代码:
	import java.awt.*;

	import java.awt.event.ActionEvent;
	import java.awt.event.ActionListener;

	public class 测试平台 {

		public static void main(String[] args) {
			// TODO Auto-generated method stub

			Frame f = new Frame ();
			Button b1 = new Button("OK");
			f.add(b1);

			AA aa = new AA();
			b1.addActionListener((ActionListener) aa);
			
			f.pack();//按钮适应窗口大小
			f.setVisible(true);
			
		}

	}
	class AA implements ActionListener
	{
		public void actionPerformed(ActionEvent a)
		{
			System.out.printf("世界!\n");
		}
	}

事件处理与窗口关闭代码
import java.awt.*;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;


public class 事件处理 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Frame f = new Frame ();
		Button b1 = new Button("OK");
		f.add(b1);
		
		
		f.addWindowListener(new NN() );
		
		
		
		NJ n = new NJ();
		b1.addActionListener((ActionListener) n);
		
		
		f.pack();
		f.setVisible(true);
		
	}

}

class NJ implements ActionListener
{
	public void actionPerformed(ActionEvent a)
	{
		System.out.printf("世界!\n");
	}
	
}

class NN extends WindowAdapter 
{

/*WindowListener 中有很多抽象方法 ,如果NN实现接口,
  却不重写这些抽象方法,则NN会变成抽象类,但很明显这
  不是我们想达到的效果
 我们只想 调用关闭窗口的方法

方法一: 重写NN"实现"WindowListener接口中的全部抽象类方法

方法二:NN extends WindowAdapter 
public void windowClosing(WindowEvent arg0) {
		// TODO Auto-generated method stub
		System.exit(-1);

	
*/
	/*
	@Override
	public void windowActivated(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowClosed(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		// TODO Auto-generated method stub
		System.exit(-1);
	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowIconified(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowOpened(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	*/
	public void windowClosing(WindowEvent arg0) {
		// TODO Auto-generated method stub
		System.exit(-1);}
}
三个文本框
import java.awt.*;
import java.awt.event.*;
public class 测试平台 {
	
	public static TextField t1,t2,t3;
	//公有,静态
	public static void main(String[] args) {
	
		Frame f = new Frame();
		 t1 = new TextField(30);
		 t2 = new TextField(30);
		 t3 = new TextField(30);
		
		//Label 标签
		Label Lb = new Label("+");
		Button b = new Button("=");
		f.setLayout(new FlowLayout());
		f.add(t1);
		f.add(Lb);
		f.add(t2);
		f.add(b);
		f.add(t3);
		
		b.addActionListener(new CL());
	
		f.pack();
		f.setVisible(true);
		
		
		
	}
}


class CL implements ActionListener
{
	@Override
	public void actionPerformed(ActionEvent a)
	{
		String str1 = 测试平台.t1.getText();
		String str2 = 测试平台.t2.getText();
		int num1 = Integer.parseInt(str1);
		int num2 = Integer.parseInt(str2);
		
		
		String str3 = Integer.toString(num1 + num2);
		
		测试平台.t3.setText(str3);
		
	}
}
/*
该程序缺点:
1.主函数代码过多
2.程序逻辑混乱

解决:
直接创建新的类
在创建一个方法,把代码放入方法中就可
*/
/*
	2009年6月29日10:34:02
	文本框内容相加 方法二:
		通过在B类中定义A类的属性,就可以达到在B类访问A类成员目的
		但是通过这种方式无法访问A类私有成员
		
		本方式既繁琐又有局限性,不推荐
*/

import java.awt.*;
import java.awt.event.*;

public class 测试平台2{
	
	public static void main(String[] args)
	{
		TF tf = new TF();
		tf.launch();			 
	}
}

class TF
{
	public TextField tf1, tf2, tf3;
	
	public void launch()
	{
		tf1 = new TextField(30);
		tf2 = new TextField(30);
		tf3 = new TextField(30);
		Button bn = new Button("=");
		Label Lb = new Label("+");
		Frame f = new Frame("文本框相加示例");
		f.setLayout(new FlowLayout());
		f.add(tf1);
		f.add(Lb);
		f.add(tf2);
		f.add(bn);
		f.add(tf3);
		
		bn.addActionListener(new MyMonitor(this));
		
		f.pack();
		f.setVisible(true);
	}
}

class MyMonitor implements ActionListener
{
	private TF tf;
	
	public MyMonitor(TF tf)
	{
		this.tf = tf;
	}
	
	@Override
	public void actionPerformed(ActionEvent e)
	{
		String str1 = tf.tf1.getText();
		String str2 = tf.tf2.getText();
		int num1 = Integer.parseInt(str1);
		int num2 = Integer.parseInt(str2);
		int num3 = num1 + num2;
		
		tf.tf3.setText(num3+"");
	}
}
计算器


内部类

1.定义:A类的内部但是所有方法的外部定义了一一个B类,则B类就是A类的
	内部类,AB的外部类

2. 可以把内部类当做包裹它的外部类的一个成员,这是理解内
  部类的关键

3.内部类的优点:
		1>内部类的所有方法都可以访问外部类的所有成员
		2>增加程序的安全性,有效避免其他不相关类对该类的访问
4.何时使用
	如果一个B类要使用A类的所有成员,并且B类不需要被除A类以外的
	其他类访问,则我们应当把B类定义为A类的内部类
											【TestTextField 1.java】
											【TestTextField_ 2.java】
											【TestTextField 3.java】



匿名类





java.awt		抽象窗口工具包,调用本地系统方法实现功能需求
java.swing		基于awt,跟多组件,完全有java实现,轻量,可移植

"顶层容器
awt    Frame
swing  JFrame 
"中间容器[非必须]
充当基本组件的容器,不可独立显示
awt     Panel
swing   JPanel

"常用控件
JPanel			//添加面板
JLabel 			//添加标签
JTextField 		//添加文本框
ButtonGroup 	//单选按钮组
JRadioButton 	//单选按钮
JCheckBox 		//复选按钮
JList 			//下拉表
JComboBox 		//列表框

    

5>IO

什么叫流

1.引入代码:
        package 流;
        import java.io.*;
        public class TestFileReader {
            public static void main(String[] args)throws Exception 
            {
                // TODO Auto-generated method stub
                    FileReader fr = new FileReader("D:\\桌面文件\\二叉树.txt");
                //注解:①
                    int ch;//整型数值
                    ch = fr.read();//返回该字符的二进制  整型数值

                    while(ch!=-1)//【文件读取到末尾返回-1 】【字符从0开始】 
                    {
                            System.out.printf("%c", (char)ch);
                            ch = fr.read();//【文件指针自动后移】
                    }
                fr.close();
            }
        }  
 /*
 注解①:
	1.fr产生,fr叫流,或流对象
	2.结构:
						fr管道	
		【程序】<=================== 【文件】

		注意:箭头指向程序"即从文件中读数据"
		fr.read()相当于管道上的小按钮       	
 */

2.流与类的关系
   定义:"用于程序和设备之间传输数据的管道",
    	是一个"特殊的类",则这个类有一个新
    	的名字叫流//例如:FileReader
    
    流一定是类,但类不一定是流

流的分类

1.流有多种分类方法,可按照不同角度划分:
	按数据流的方向不同可以分为输入流和输出流。
    按处理数据单位不同可以分为字节流[一个字节]和字符流[两个字符]。
    按照功能不同可以分为节点流和处理流。

2.J2SDK所提供的所有流类型位于包java.io内都分别继承自以下四
	种抽象流类型。

字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter
3.原始流与包裹流关系
	[即节点流和处理流的关系]    
四大基本抽象流
'InputStream、OutputStream、Reader、Writer'
1.	在java中一个字符占用两个字节
    
2.	InputStreamOutputStream读写数据的单位是一个字节
	ReaderWriter读写数据的单位是一个字符
    
3.	InputStreamOutputStreamReaderWriter都是抽象类,或者说
	都是抽象流,通常我们使用的都是它们的子类
 
我的理解:以程序本身的视角读与写
    	InputStreamReader   程序读
    	OutputStreamWriter  程序写
InputStream
   
//@-----------------------InputStream-----------------------------InputStream为例学习四种抽象流:
 InputStream常用方法:
 1> public int read() throws IOException
        读取一个"字节"并以整数形式返回
        如果读取到输入流的末尾则返回-1
    
2> public int read(byte []b);throws IOException
	'1' 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
		以整数形式返回实际读取的字节数
    
	'2' 如果b的长度为0,则不读取任何字节并返回0;如果因为流位于文
        件末尾而没有可用的字节,则返回值-1;

    例子:
    FileInputStream fis = new FilelnputStream("d:\\share\\errorlog.txt");
    int len = fis.read(buf); //注解②

    "文件" -> "程序"
    /*注解②:
    		"文件" -> "buf数组"
            从fis流所联的d:\\share\\errorlog.txt文件中
            读取数据,并将读取出来的数据写入buf数组中,返回值是实际写入
            buf数组的字节个数,如果读取到文件的结尾,则返回-1

            buf是数组名.length >= len

            while()
            {
                byte [] buf = new byte[1000];
                len = fis.read(buf);
            }

            1M多的文件,循环读取,不停对len在最后一次中
            可能就会小
    */

3> 
public int read(byte[] b, int off, int len) throws IOException     
     /*从调用read的方法的对象所关联的设备中读取
     	字节放到b所在的数组中*/      
    '1'从输入流中最多读取len个字节的数据并存入byte数组中
    '2'"b表示读取的数据要存入的数组的名字
    '3'"off表示第一个读出的数据要存入的位置,是下标
    '4'len表示最多能读取的字节数
    '5'将从输入流所关联到的设备中读取的第一个字节存储在元素
       b[off]中,下一个字节存储在b[off+1]中,依次类推。
        "读取的字节数最多等于len
    '6'尝试读取len个字节,但读取的字节也可能小于该值。以整数形
       式返回实际读取的字节数
    '7'如果读到了文件的末尾,则返回-1 .

4>
    void close()  throws IOException//重要
    关闭此输入流并释放与该流关联的所有系统资源
    long skip(long n) throws IOException
    跳过和丢弃此输入流中数据的n个字节。
    这个用的很少

//---------------------------------------------------------------
OutputStream
//@-----------------------OutputStream-----------------------------
1.OutputStream流中常用的方法
    "程序" -> "文件"
        //向输出流中写入一个字节数据,该字节数据为参数b的低8位
        void write (int b) throws IOException
    
        //将一个字节类型的数组中的数据写入输出流
        void write (byte[] b) throws I0Exception
    
        //将一个字节类型的数组中的从指定位置(off)开始的
        //len个字节写入到输出流
        void write (byte[] b, int off ,int len)throws IOException
    
        //关闭流释放内存资源
        void close() throws IOException
        //将输出流中缓冲的数据全部写出到目的地
        void flush() throws IOException
    
        "true"
        输入流.read(buf);
        输出流.write(b);

/*----------
error:
输出流.read(buf);
输入流.write(b);
----------*/

Reader
     //读取一个字符并以整数的形式返回(0~255) ,
    //如果返回-1已到输入流的末尾。
    int read() throws IOException
    //读取一系列字符并存储到一个数组buffer,
    //返回实际读取的字符数,如果读取前已到输入流的末尾返回-1
    int read(char[] cbuf) throws IOException
    //最多读取length个字符
    //并存储到一个数组buffer,从length位置开始
    //返回实际读取的字符数,如果读取前以到输入流的末尾返回-1
    int read(char[] cbuf, int offset, int length)
    throws IOException
    //关闭流释放内存资源
    void close () throws IOException
    //跳过n个字符不读,返回实际跳过的字节数
    long skip (long n) throws IOException

Writer
    //向输出流中写入一个字符数据,该字节数据为参数b的低16位
    void write (int c) throws IOExcepti on
    //将一个字符类型的数组中的数据写入输出流,
    void write (char [ ] cbuf) throws IOE xception
    //将一个字符类型的数组中的从指定位置(offset)开始的
    //length个字符写入到输出流
    void write (char[] cbuf, int offset,int length)
    throws IOException
    //将一个字符串中的字符写入到输出流
    void write (String string) throws IOException
    //将一个字符串从offset开始的length个字符写入到输出流
    void write (String string, int offset, int length)
    throws IOException
    //关闭流释放内存资源
    void close () throws IOException
    //将输出流中缓冲的数据全部写出到目的地
    void flush() throws IOException

字节流与字符流的使用区别
1. "字符流读写文本文件
    package;
    import java.io.*;
    public class TestReadtoWrite {

        public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
            FileReader fr = new FileReader
               ("D:\\English\\eclipse-jee-photon-R-win32\\java高级\\src\\流					\\TestReadtoWrite.java");
            FileWriter fw = new FileWriter("d:\\桌面文件\\a.txt");
            
            int binaryNumber;//二进制数
            binaryNumber = fr.read();
            while(-1!=binaryNumber) 
            {
                fw.write(binaryNumber);
                binaryNumber = fr.read();
            }
            
            //输出流刷新
            fw.flush();

            //关闭
            fr.close();
            fw.close();

        }

    }

"输出流中存在 flush() 方法
"不刷新可能写入失败
2.字符流无法处理非文本文件 
    
3.字节流读取非文本文件
    package;
    import java.io.*;


    public class 字节流读取非文本文件测试 {

        public static void main(String[] args) throws Exception
        {
            // TODO Auto-generated method stub
            //D:\桌面文件\CSS\music\TestMusic.mp3
            FileInputStream   fis = new FileInputStream("D:\\桌面文件						\\CSS\\music\\TestMusic.mp3");
            
            FileOutputStream  fos = new FileOutputStream("D:\\a.mp3");
            int binaryNumber = 0;
            binaryNumber = fis.read();
            while(-1!=binaryNumber) {
                fos.write(binaryNumber);
                binaryNumber = fis.read();
            }

            fos.flush();

            fis.close();
            fos.close();

            /*---------------------------
            运行成功

            .mp3可以听
            同理可测试其他的非文本文件

            ---------------------------*/		
        }
    }
//@-------------------------总结--------------------------
1. FileInputStreamFileOutputStream可以完成所有格式文件的赋值
    
2. FileReaderFileWriter只可以完成文本文件的复制,却无法完成视频
    格式文件的复制
        '1'因为字节是不需要解码和编码的,将字节转化为字符才存在解码和解码的问题
        '2'字节流可以从所有格式的设备中读写数据,但字符流只能从文本格式的设备中
        	读写数据

文件流
1.文件流包括
    FilelnputStream FileOutputStream  -字节流
    FileReader      FileWriter		  -字符流

2.FilelnputStream的使用
    '1'	InputStream是用来读取字节的,是个抽象类,我们通常使
    	用的是该类的子类
    '2'	FilelnputStreamInputStream的子类,利用
    	FilelnputStream可以将一个文件的内容按字节为单位读取出来
    
    '3'FilelnputStream有一个很常用的构造函数
        ■ public FileInputStream(String fileName) throws FileNotFoundException
        ■ 利用该构造函数可以实现将输入流连接到某个文件的功能
        ■ 必须对本构造函数抛出的异常进行捕捉
        ■ 如果用字符串来表示操作系统的文件路径时,我们可以使用"\\""/"两种方式来作为文
          件夹的路径分隔符
        ■FileOutputStream同理,不再赘述

    
缓冲流
1.缓冲流概述:
    缓冲流就是带有"缓冲区""输入输出流"
    缓冲流可以显著的减少我们对IO访问的次数,保护我们的硬盘!
    缓冲流本身就是"处理流"(处理流也叫包裹流)
    缓冲流必须得"依附于节点流"(节点流也叫原始流)
    处理流是包裹在原始节点流上的流,相当于包括在管道上的管道!
    
 			 " 包裹流"
    "_______________________________"
    		___________________________________
    			原始流
    		___________________________________
    "_______________________________"
    
2.缓冲流要"套接"在相应的节点流之上,对读写的数据提供了缓冲的功能,
  提高了读写的效率,同时增加了一些新的方法。
  J2SDK提供了四种缓存流,其常用的构造方法为:
        BufferedReader (Reader in)
        BufferedReader (Reader in, int sz) //sz 为自定义缓存区的大小
        Bufferedwriter (writer out)
        Bufferedwriter (Writer out,int sz)
        BufferedInputstream (Inputstream in)
        BufferedInputStream (Inputstream in, int size)
        Bufferedoutputstream( Outputstream out)
        Bufferedoutputstream (Outputstream out,int size)

3.
    缓冲输入流支持其父类的mark和reset方法。
    BufferedReader 提供了 readLine 方法用于读取一行字符串[以r或\n分隔]
    BufferedWriter 提供了 newLine  用于写入一个行分隔符。
    对于输出的缓冲流,写出的数据会先在内存中缓存,使用flush方法将会使内存中的数据
    立刻写出。

4.缓冲流[读写文件代码] 
    package;
    import java.io.*;
    public class 缓冲流Buffered__ {

        public static void main(String[] args)throws Exception {
            // TODO Auto-generated method stub
            BufferedInputStream   bis = 
            new BufferedInputStream(new FileInputStream("D:\\桌面文件						\\CSS\\music\\TestMusic.mp3"));
            BufferedOutputStream  bos = 
            new BufferedOutputStream( new FileOutputStream("D:\\a5.mp3"));
            byte []buf = new byte[1024];
            int len = 0;
            len = bis.read(buf);//程序从文件中读入数据,写入buf数组
            while(-1!=len) {
                bos.write(buf,0,len);//程序从buf数组读出数据,
                len = bis.read(buf);
            }

            bos.flush();
            bos.close();
            bis.close();

            System.out.println("OK!");
        }
    }

5.BufferedOutputStream 和 BufferedInputStream
    '1'BufferedOutputStream:带缓冲的输出流, 允许一次向硬盘写
    		入多个字节的数据
    '2'BufferedInputStream:带缓冲的输入流,允许一次向程序中读
    		入多个字节的数据
    '3'"BufferedOutputStreamBufferedInputStream都是包裹流,
       "必须的依附于OutputStreamInputStream
            例子:	
            利用BufferedOutputStreamBufferedInputStream完成大容量文
            件的复制,这远比单纯利用FilelnputStreamFileOutputStream
            要快得多



6.易错点:
    '1':
    BufferedInputStream bis = new BufferedInputStream(
    new FileInputStream("D:\l综艺\电影\猫和老鼠\CD4.rmvb")); 
    //bis 输入流有个默认的缓冲区,大小为32个字节
    byte[] buf= new byte[1024];
    int len = bis.read(buf, 0, 1024);
            /*
            一定要注意,bis.read(buf, 0, 1024);这不是从buf中读数据,而是从
            bis所关联到的“D:综艺\电影\猫和老鼠\CD4.rmvb”文件中读取数
            据,并将读取的数据写入bis自己的默认缓冲区中,然后再将缓冲区
            的内容写入buf数组中,每次最多向buf数组中写入1024个字节,返
            回实际写入buf数组的字节个数,如果读到了文件的末尾,无法再向
            buf数组中写入数据,则返回-1
            */
	'2':
        BufferedInputStream流中有
        	public int read(byte[] b)
        	方法用来把从当前流关联到的设备中读取出来的数据存入一
        	个byte数组中
            
        BufferedOutputStream流中有
        	public int write(byte[] b)
        	方法用来把byte数组中的数据输出到当前流所关联到的设备中
            
        如果我们希望用BufferedInputStreamBufferedOutputStream
        完成“将一个设备中的数据导入另一个设备中”,我们就应该定义一
        个"临时的byte类型的数组",用这个临时数组作为输入流与输出流进
        行交互的"中转枢纽"!

6.注意:
	'1'
     BufferedInputstream BufferedOutputStream要比
	FileInputStream FileOutputStream读写数据的速度快
    
    '2'
        我们"只有
            BufferedInputStream
            BufferedOutputStreamBufferedWriter
            BufferedReader
        "没有
            BufferedStream
            BufferedFileInputStream(但有FileOutputStream)
            BufferredFileOutputStream (但有FileInputStream)
            BufferedFileReader(但有FileReader)
            BufferedFileWriter(但有FileWriter)
        "所以前四个流都是包裹流

            
7.BufferedReader 和 BufferedWriter
            
'1'代码:
package;
/*
利用 BufferedReader 和 BufferedWriter 完成文本文件的复制
*/
    import java.io.*;
    public class BufferedReaderAndbufferedWriter
    {
        public static void main(String[] args)t	hrows Exception
        {
            BufferedReader br = null;
            BufferedWriter bw = null;
            try
            {
                br = new BufferedReader(
                new FileReader("d:\\English\\eclipse-jee-photon-R-win32\\java高级				\\src\\流\\BufferedReaderAndbufferedWriter.java"));
                bw = new BufferedWriter(
                            new FileWriter("d:\\Writer.txt"));
                String str = null;

                while (null != (str=br.readLine()))  //从此处是null
                    /*br.readLine()读取一行字符,但会将读取的换行符自动丢弃,
                    即返回的String对象中并不包括换行符*/
                {
                    bw.write(str);
                    bw.newLine();  //写入一个换行符  这行不能省
                }
                bw.flush();
            }
            catch (FileNotFoundException e)
            {
                e.printStackTrace();
                System.exit(-1);
            }
            catch (IOException e)
            {
                e.printStackTrace();
                System.exit(-1);
            }
            finally
            {
                try
                {
                    bw.close();
                    br.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                    System.exit(-1);
                }
            }
        }
    }
	'2'小结:
        Reader FileReader InputStream FileInputStream
        BufferedInputStream流中都没有readLine方法
        DatalnputStream流中有readLine方法,但已经被标记为过时
        BufferedReader流中有readLine方法,并且该方法是可以正确被使用的
        BufferedReader流中有readLine是个非常有用的方法,
        BufferedReader是个要经常使用的流
        利用BufferedReaderBufferedWriter可以提高读写文本文件内容的速度

数据流
DatalnputStreamDatalOutputStream

1.DatalnputStream能够以一种与机器无关的方式,直接从底层字节输入流读
  取Java基本类型和Srina类型的数据,常用方法包括
        常见方法:
            public DatalnputStream(InputStream in)
            public final boolean readBoolean(
            public final byte readByte()
            public final char readChar()
            public final double readDouble()
            public final float readFloat()
            public final int readInt()
            public final long readLong()
            public final short readShort()
            public final String readUTF()

    DatalnputStream是包裹流,"必须依附于InputStream

2.   DataOutputStream能够以一种与机器无关的方式,直接将Java基本类
	 型和String类型数据写出到其他的字节输出流
        常见方法:
            public DataOutputStream(OutputStream in)
            public final boolean writeBoolean()
            public final byte writeByte()
            public final char writeChar()
            public final double writeDouble()
            public final float writeFloat()
            public final int writelnt()
            public final long writeLong()
            public final short writeShort()
            public final String writeUTF()	
	DataOutputStream是包裹流,"必须依附于OutputStream

                
                
3.例子:
    编程实现将long类型数据写入byte数组,然后再从byte数组中把该数
    据读出来

	附注:
        这是Socket编程中经常要完成的功能,
        因为网络编程中经常要把数值型数据存入byte数组中,然后把byte数组打
        包成数据包(即DatagramPacket),再把数据包经过网络传输到目的机,
        目的机再从byte数组中把原数值型数据还原回来
                
	本程序要使用到
        ByteArrayInputStream
        ByteArrayOutputStream
        DatalnputStream
        DataOutputStream


1.数据流的小案例:

        //1.长整型数据
        long n = 9876543210L;		
        //2.创建 ByteArrayOutputStream baos管道
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //3.创建依附于 baos管道的 DataOutputStream 包裹流 dos管道
        DataOutputStream dos = new DataOutputStream(baos);
        //4.使用DataOutputStream中的writeLong()方法将长整型的二进制数据写入系统默认缓冲区数组
        dos.writeLong(n);
        dos.flush();
        //5.使用ByteArrayOutputStream中的toByteArray()方法将数据写入自定义byte类型数组   
        byte buf[] = baos.toByteArray();//我的理解:将默认数组可视化,可以通过数组名操作
        //6.创建ByteArrayInputStream bais管道 使用已有的buf数组作为缓冲区
        ByteArrayInputStream bais = new ByteArrayInputStream(buf);
        //7.创建依附于bais管道 的DataInputStream dis 管道
        DataInputStream dis = new DataInputStream(bais);
        //8.使用dis中的readLong()方法将缓冲区中的数据以long类型读出
        long l = dis.readLong();		
        dos.close();	

转换流
1.只有两种:"字节流""字符流"
    OutputStreamWriter流是把OutputStream流转化成Writer流的流
    InputStreamReader是把InputStream转化成Reader
    
2.OutputStreamWriter和InputStreamReader都是包裹流

3.[案例:]如何将键盘输入的字符组成字符串直接赋给String对象
    	String str    = null;
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		str = br.readLine();
		System.out.println("str = " + str);
	【该示例未增加异常捕获】【完整:TestStringInput.java】
        
4.
    String str= "123";
    BufferedReader br =new BufferedReade r( new
    InputStreamReader(System.in));

■ 如果直接输入回车 的话,则
    '1'br.readLine()会丢弃回车符,而不是返回回车符,即
       br.readLine(遇到回车符时终止读取,并且会把读取到的回
       车符自动丢弃掉
    '2'br.readLine()返回的是""而不是null,表示空字符串
		null表示空指针,空指针就是空地址,空地址就是不指向任何
		存储单元的意思

Print流
Print流只有输出,没有输入
分类:
    PrintWriter 输出字符
    PrintStream 输出字节

Object流
1.有四大抽象流:'InputStream、OutputStream、Reader、Writer'一般我们使用他们的子类
    
2.  FilelnputStream FileOutputStream  -字节流
    FileReader      FileWriter		  -字符流
    这四种可以直接连接到文件,例如: FileWriter fw = new FileWriter("d:\\桌面文件\\a.txt");

3.缓冲流都是"包裹流",所以使用前与一个流被包裹,通常是2中的四种
     	例如: BufferedWriter bw = new BufferedWriter( new FileWriter("d:\\Writer.txt"));

4.

6>容器(集合)

容器

定义
如果一个类是专门用来存放其它类对象的,则这个类有另一个特殊的词叫做容器[或者说"集合"]
为什么需容器
1.数组存在两个缺陷:
    数组长度难以扩充
    数组中元素类型必须相同
        
容器可以弥补数组的这两个缺陷
举例:.
    假设A是个类名
    A[]arr = new A[10];
    表示分配了一个数组,数组的每个元素都是A类对象的一个引用,但是如果想扩充数组的长度,
    比如希望数组的长度变成15,我们是不能直接在原数组内存的后面追加内存的,必须得另外
    分配长度为15的内存空间,然后利用System. arraycopy()方法来把原数组的内容拷贝到新内
    存中,很明显,这即耗时。又耗内存!所以一旦数组内存已分配,你想改变数组的长度,效率
    就会变的很低

容器的框架图

分类和使用

容器与现实的对应关系
	1.集合就是将若干用途、性质相同或相近的"数据"组合而成一个整体
    
	2.数学上集合类型可以归纳为三种
        集 (Set)
        	Set集合中不区分元素的顺序,不允许出现重复元素
        列表 (List)
       		List集合区分元素的顺序,且允许包含重复元素
        映射(Map)
        	映射中保存成对的"键-值"(Key-Value) 信息,映射中不能包含重复的键
        	每个键最多只能映射一个值。
    
Java设计了三个接口来对应数学上的三种集合类型,这三个
接口名字分别是Set List Map

Collection接口
1. Collection接口中的方法介绍
	int size();
		返回此collection 中的元素数
	boolean isEmpty() ;
	boolean containesAll(Collection c);
    	判断形参c所指向的集合中所有的元素是不是已经全部包含在了当前集合中
    	是,返回true,否则返回false
    lterator iteratof();
    	返回能够遍历当前集合所有元素的迭代器
	Object[] toArray()
        容器不是数组,不能通过下标的方式访问容器中的元素
        只有数组才可以通过下标来访问
	   返回一个包含此 collection中所有元素的数组
	  【TestArrayDistToArray.java】
            
    boolean add(Object e);
    	把e添加到当前集合中
    boolean remove(Object o);
    boolean addAll(Collection c);
    	把c中所有的元素添加到当前集合中
    boolean removeAll(Collection c);
    void clear();
    	把当前容器中的所有元素清除
    boolean equals(Object o);
    int hashCode() ;

2.重写toString()方法
    ■Collection c = new ArrayList();
    ······
    System.out.println(c);

    ■本语句等价于:
    [调用第一个元素的toString方法,调用第二个元素的toString方法,调用第三个元素的toString方法····]
    "强烈建议:所有添加到Collection容器中的对象都应该重写父类Object的toString方法"
List
1. List接口是Collection的子接口,实现List接口的容器类中的元素是有顺序的,而且可以重复
2. List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
3. J2SDK所提供的List容器类有 ArrayList,LinkedList.
    
Object get (int index)//获取下标为 index 的元素
Object set (int index,Object element);//将下标为index的元素修改为element
void add(int index,Object element) ;//在下标为index的位置插入为element
Object remove (int index) ;//移除
int indexof(Object o);//返回此列表中首次出现的指定元素的索引,
					//或如果此列表不包含元素,则返回 -1
int lastIndexOf((Object o);//最后一次出现o的位置

"ArrayList 与 LinkedList的比较"
ArrayListLinkedLis部都实现了List接口中的方法,但两者内部实现不同
ArrayList底层采用"数组"完成,而LinkedList则是以一般的"双向链表"完成,
    其内每个对象除了数据本身外,还有两个引用,分别指向前一个元素和后一个元素。
如果我们经常在List的开始处增加元素,或者在List中进行播
入和删除操作,我们应该使用LinkedList,否则的话,使用
ArrayList将更加快速
    -ArrayList存取速度快,插入删除慢
    -LinkedList存取速度慢,插入删除速度快

Set
1.因为SetList都是继承自Collection接口,所以SetList中有很多方法是一样的
List接口中有 add,set, indexOf方法,但是Set接口中却只有add方法,没有set, indexOf方法,因为Set是无序不能重复的,不存在某元素具体位置这个概念
    


2.Set接口是Collection的子接口,Set接口没有提供额外的方法,
	即:Set中所有方法都来自Collection

3.J2SDKAPI中所提供的 Set容器类有 HashSet, TreeSet4.Set容器可以与数学中“集合”的概念相对应

5.存放入HashSet 容器中的类必须要实现 equals()和hahsCode方法,
	Set"不允许重复"需要程序员手书写额外的代码实现
        复习:equals方法默认比较"内存地址"
        	相同吗?
        		相同:true
			   不相同:false 
         改写:比较"内容"是否相同
        		相同:true
        		不相同:false 
        
6.为什么要重写equals()hashCode()方法
	预备知识:
        1>散列码:
            Object中的hashCode方法会返回该对象的内存真实地址的整数
            化表示,这个形象的不是真正地址的整数值就是哈希码
        2>"过程
          /*向HashSet中添加对象时,HashSet先通过该对象的 hashCode()计算出
            相应的桶,然后再根据equals()方法找到相应的对象。如果容器中已存在该
            对象则不再添加,如果不存在,则添加进去!
         */
 
7."什么类必须得重写equals()hashCode()方法
    Hashtable HashSet HashMap都必须的同时实现 equals()方法和 hashCode(方法,
    TreeSetTreeMap则不需要实现equals(方法和hashCode()方法

8."怎样重写equals()hashCode()方法
	利用系统重写了自带类的hashCode方法
       @Override
      public int hashCode(Object obj)
     {
            return new Integer(id).hashCode;
      }
    ----------------------------------------
     public int hashCode(Object obj)
     {
            return new String(id + name).hashCode;
      }                       
    只需要保证对于相同的内容,hashCode返回相同的值即可
                                
9.TreeSet类
            1>TreeSet类实现了Set接口
            2>TreeSet是一个有序集合,TreeSet中元素将按照升序排列
                缺省是按照自然顺序进行排列,因此TreeSet中元素要实现
                Comparable接口
            3>记住:所有可以进行排序的类都应该实现Comparable接口
            4>TreeSet实例
                    Collection c = new TreeSet();
                    c.add(""123");
                    c.add("456");
                    c.add("234);
                    c.add("111"");
                    c.add(""678'");
                    Iterator it= c.iterator();
                    while (it.hasNext(){
                         System.out.println(it.next());
                    }

10.HashSet和TreeSet的比较
    HashSet是基于Hash算法实现的,其性能通常都优于
    TreeSet。我们通常都应该使用HashSet,在我们需要排序的
    功能时,我们才使用TreeSet
import java.util.HashSet;
import java.util.Set;
class Students
{
	private int id;
	private String name;
	
	public Students (int id ,String name) {
		this.id =id;
		this.name= name;
		
	}
	@Override
	public String toString() {
		return  this.id + "," +  this.name;
	}
	@Override 
	public int hashCode()
	{
//		return id*this.name.hashCode();
		return new String(id+name).hashCode();
	}
	@Override 
	public boolean equals(Object obj)
	{
		Students stu = (Students)obj;
		return this.id == stu.id&&this.name == stu.name;
	}
	
}

public class TestHashCode {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Set S = new HashSet();
		S.add(new Students(12,"张三"));
		S.add(new Students(15,"李四"));
		S.add(new Students(15,"李四"));
		S.add(new Students(12,"张三"));
		S.add(new Students(12,"王五"));
		System.out.println(S);//输出顺序可能与添加顺序不同
	}
}

Collections
Collection接口的实现类,如ArrayListLinkedList本身
并没有提供排序,倒置,查找等方法,这些方法是由
Collections类来实现的,该类有很多public static方法,可
以直接对Collection接口的实现类进行操作

"Collections类常用算法"
类 java.uti1.collections 提供了一些静态方法实现了基于List容器的一些常用算法.

void sort(List)List容器内的元素排序
void shuffle(List)List容器内的对象进行随机排列
void reverse(List)List容器内的对象进行逆续排列【倒置】
void fill(List, Object)用一个特定的对象重写整个List容器
void copy (List dest,List src)将src List容器内容拷贝到dest List容器
    										【dest:目的 src:源】
int binarySearch(ListObieet)对于顺序的List容器,采用折半查找的方法查找特定对象
//记住,使用binarySearch()方法的前提是该容器已升序排序,且只能是升序
 若是降序,则先倒置

+---------------------------------------------------+

List lt=new LinkedList(); /7行
it.add("111");
It.add("222");
It.add("333");
Svstem.out.printIn(lt);
Collections.fill(lt ,"888");
System.out.printIn(It);

[111,222,333]
[888,888,888]
+---------------------------------------------------+                                              
Comparale接口

基本类型数据和String类型数据,它们彼此的比较标准Java语言本身已经提供好了
用户"自定义类对象"之间比较的标准Java语言本身是没有提供
所以如果一个容器中含有用户自定义类型的数据,并且我们
需要对容器中元素进行"排序",或"查找"某一元素时,我们就必
须得制定容器中元素与元素之间比较的标准
凡是需要进行对象比较/排序的场合均可考虎实现Comparable接口
    

class Student implements Comparable{
	private int id;
	private String name;
	
	public Student (int id ,String name) {
		this.id =id;
		this.name= name;
		
	}
	@Override
	public String toString() {
		return  this.id + "," +  this.name;
	}
	@Override
	public int compareTo(Object o) {
		// TODO Auto-generated method stub
		Student stu = (Student)o;
        //子类特有属性无法被父类使用,所以向下转型
		if(this.id==stu.id)
			return 0;
		else if(this.id>stu.id)
				return 1;
		else 
			return -1;
	
	}
}

public class TestList {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ArrayList L = new ArrayList();
		L.add(new Student(12,"张三"));
		L.add(new Student(15,"李四"));
		L.add(new Student(12,"王五"));
		
		Collections.sort(L);
		System.out.println(L);
		
	}
}

所有可以"排序"的类都实现了java.1ang.Comparable 接
口,Comparable接口中只有一个方法
public int compareTo(object obj);该方法
返回0表示    this==obj
返回正数表示 this> obj
返回负数表示 this< obj
实现了Comparable 接口的类通过实现 compareTo 方法从
而确定该类对象的排序方式。

   
    
Iterator接口
"通过以上的学习我们知道对于不同的集合,其内部的存储结构不同的"
1.Ilterator接口用来以统一的方式对集合中的各个元素进行遍历
2.Iterator接口的对象又称为迭代器,利用该对象可以方便的遍
  历容器中的元素
3.所有实现了Collection接口的容器类都有一个Iterator()方法
  该方法返回一个实现了Iterator接口的对象

4.Ilterator方法介绍
   
    1>示意图:												   
          ---------------------------------------			  
     	游标 ↑   next() ↑			元素		
    【返回游标划过元素】
	2>boolean hasNext():
		是用来判断当前游标的后面还是否存在元素,如果存在返回直,否则返回假  
	3>Object next();
		先返回当前游标右边的元素,然后游标后移一个位置

    4>void remove()
        删除最近返回的元素,在调用remove之前,我们至少保证先调用一次
        next方法,而且调用next之后只能调用一次remove方法
        remove()方法"不推荐使用"
            






Map
java.util.Map接口描述了映射结构,Map结构允许以键集、
值集合或键~值映射关系集的形式查看某个映射的内容。
    
1.主要方法:
    Object put(Object key, Object value)
    Object get(Object key)
		注意Map接口中并没有Object get(Object value)
    boolean isEmpty()
    void clear()
    int size()
    boolean containsKey(Object key)
    boolean containsValue(Object value)
        
2.预备知识:哈希表
    哈希表的定义:
        哈希表不是只存储需要保存的数据,而是既保存数据,也保存该数据的主键,实际是。
        先保存主键,然后哈希表会根据某种算法自动计算出以当前主键为主键的数据的存储位
        置,然后再把该数据保存进去
    哈希表:
        假设待保存的数据是val,val的主键是key,则哈希表是先存储key,然后哈希表会自动
        根据key计算出val的存储位置,并最终把val存储进去
    哈希表注意事项:
        Hash即哈希表又称散列表
        哈希表主要是为了提高数据的存储速度和查找速度而设计的
        哈希表是人类的一种追求,人很难设计出完美的哈希表
        几乎所有的哈希表都会产生哈希冲突
        Java中是利用桶来解决哈希冲突的

        

小结

1.定义:
    如果一个类是专门用来存放其它类对象的,则这个类有
    另一个特殊的词叫做容器
    
2.容器和类的关系:
	容器是类,类不一定是容器
    
3.接口
        1.Collection 接口:
            Set 接口:
            	无序,不允许重复
            实现类:
            	TreeSet HashSet
        2.List 接口:
            	有序,允许重复
            实现类:
           		 ArrayList LinkedList
        3. Map 接口:
            定义:
           		 既保存数据本身,也保存数据主键的一种接口
            实现类:
            	HashMap TreeMap
    
4. HashCode()equals()方法
	参见PPT
    
5.Collections 类:
	该类提供对Collection 接口实现类的排序、倒置、查找等功能
    
6.Comparable 接口:
	通过该接口的方法可以制定出对象之间比较的标准
	凡是需要进行对象的比较排序的场合考虑实现该接口
    
7.Iterator 接口:
    利用接口提供的方法我们可以遍历所有容器中的元素

网络编程基础

基本概念

1.网络程序
    能够"接受另一台计算机发送过来的数据"或者能够"向另一台计算机发送数据"的
    程序叫做网络程序

2.IP:
能够在网络中唯一标示一台主机的编号就是IP
网络中每台主机都必须有一个惟一的IP地址;
IP地址是一个逻辑地址;
因特网上的IP地址具有全球唯一性;
32位,4个字节,常用点分十进制的格式表示,例如:192.168.0.16


歧萌天下https://

Object

toString


1.所有的类都默认自动继承了Object2.Object类中的toString方法返回的是类的名字和该对象哈希码组成的一个字符串 
3.System.out.println(类对象名);
    实际输出的是该对象的toString()方法所返回的字符串
    calss A
    {
    }
    public class TestA
    {
        public static void main (String []args)
        {
            A aa = new A();
            System.out.println(aa);
            //等价于System.out.println(aa。toString());
        }
    }
    /*
    运行结果:A@de6ced 
    类名@aa对象保存地址十六进制
    */
4.为了实际需要,建议子类重写父类Object继承的toString方法
    public String toString (){
        
    }
+-------------------------------------------------+
对任意类A,假设aa是该A类的一个实例
System.out.println(aa); 等价于System.out.println(aa.toString());
Object 类中含有 toString方法
Java中所有的类默认都继承了Object的toString方法
建议所有的子类都重写toString方法         
+-------------------------------------------------+

equals

1.所有的类都从Object类中继承了equals方法
2.Object类中equals方法源代码:     
  public boolean equals(Object obj)
        {
                return this == obj;
        }
3.如果是同一块内存,则Object中的equals方法返回true,如果是不同的内存,则返回false
4.如果希望不同内存,但相同内容的两个对象,调用equals时返回true,则我们需要重写父类的
  equals方法

5.重写代码:
class A
{
	int i;
	public N(int i)
	{
		this.i = i;
	}
	public boolean equals(Object obj)
	{
		 aa = (A)obj;
		if(this.i==aa.i)
			return true;
		else
			return false;
	}

}
	
public class Equals_1 {
	
	public static void main (String []args)
	{
		A aa = new N(2);
		A bb = new N(2);
		System.out.printf("%b \n",aa.equals(bb));
	}
}
6.注意:String中的equals方法已经被重写了
    String str1 = "abc";
    String str2 = "abc";
    str.equals(str2);//返回结果为 true
	

字符串比较


Java字符串比较(3种方法)以及对比 C++ 时的注意项
字符串比较是常见的操作,包括比较相等、比较大小、比较前缀和后缀串等。在 Java 中,比较字符串的常用方法有 3 个:equals() 方法、equalsIgnoreCase() 方法、 compareTo() 方法。

其中最常用的是 equals() 方法,下面详细介绍这 3 个方法的使用。

equals() 方法
equals() 方法将逐个地比较两个字符串的每个字符是否相同。如果两个字符串具有相同的字符和长度,它返回 true,否则返回 false。对于字符的大小写,也在检查的范围之内。equals() 方法的语法格式如下:

str1.equals(str2);
str1 和 str2 可以是字符串变量, 也可以是字符串字面量。 例如, 下列表达式是合法的:

"Hello".equals(greeting)
下面的代码说明了 equals() 方法的使用:

String str1 = "abc";
String str2 = new String("abc");
String str3 = "ABC";
System.out.println(str1.equals(str2)); // 输出 true
System.out.println(str1.equals(str3)); // 输出 false1
在第一次进入系统时要求管理员设置一个密码,出于安全考虑密码需要输入两次,如果两次输入的密码一致才生效,否则提示失败。具体实现代码如下:

public static void main(String[] args) {
    String sys = "学生信息管理";
    System.out.println("欢迎进入《" + sys + "》系统");
    System.out.println("请设置一个管理员密码:");
    Scanner input = new Scanner(System.in);
    String pass = input.next(); // 设置密码
    System.out.println("重复管理员密码:");
    input = new Scanner(System.in);
    String pass1 = input.next(); // 确认密码
    if (pass.equals(pass1)) { // 比较两个密码
        System.out.println("已生效,请牢记密码:" + pass);
    } else {
        System.out.println("两次密码不一致,请重新设置。");
    }
}
运行该程序,由于 equals() 方法区分大小写,所以当两次输入的密码完全一致时,equals() 方法返回 true,输出结果如下所示:

欢迎进入《学生信息管理》系统
请设置一个管理员密码:
abcdef
重复管理员密码:
abcdef
已生效,请牢记密码:abcdef
否则输出如图下所示的结果:

欢迎进入《学生信息管理》系统
请设置一个管理员密码:
abcdef
重复管理员密码:
aBcdef
两次密码不一致,请重新设置。
equalsIgnoreCase() 方法
equalsIgnoreCase() 方法的作用和语法与 equals() 方法完全相同,唯一不同的是 equalsIgnoreCase() 比较时不区分大小写。当比较两个字符串时,它会认为 A-Z 和 a-z 是一样的。

下面的代码说明了 equalsIgnoreCase() 的使用:

String str1 = "abc";
String str2 = "ABC";
System.out.println(str1.equalsIgnoreCase(str2));    // 输出 true2
在会员系统中需要输入用户名和密码进行检验,下面使用 equalsIgnoreCase() 方法实现检验登录时不区分用户名和密码的大小写,具体的代码实现如下所示。

public static void main(String[] args) {
    String sys = "学生信息管理";
    System.out.println("欢迎进入《" + sys + "》系统");
    System.out.println("请输入管理员名称:");
    Scanner input = new Scanner(System.in);
    String name = input.next(); // 获取用户输入的名称
    System.out.println("请输入管理员密码:");
    input = new Scanner(System.in);
    String pass = input.next(); // 获取用户输入的密码
    // 比较用户名与密码,注意此处忽略大小写
    if (name.equalsIgnoreCase("admin") && pass.equalsIgnoreCase("somboy")) { // 验证
        System.out.println("登录成功。");
    } else {
        System.out.println("登录失败。");
    }
}
在上述代码中,由于使用 equalsIgnoreCase() 方法进行比较,所以会忽略大小写判断。因此输入 ADMIN 和 SOMBOY 也会验证通过,如下所示:

欢迎进入《学生信息管理》系统
请输入管理员名称:
ADMIN
请输入管理员密码:
SOMBOY
登录成功。
否则输出结果如下所示:

欢迎进入《学生信息管理》系统
请输入管理员名称:
admin
请输入管理员密码:
sommboy
登录失败。
equals()==的比较
理解 equals() 方法和==运算符执行的是两个不同的操作是重要的。如同刚才解释的那样,equals() 方法比较字符串对象中的字符。而==运算符比较两个对象引用看它们是否引用相同的实例。

下面的程序说明了两个不同的字符串(String)对象是如何能够包含相同字符的,但同时这些对象引用是不相等的:

String s1 = "Hello";
String s2 = new String(s1);
System.out.println(s1.equals(s2)); // 输出true
System.out.println(s1 == s2); // 输出false
变量 s1 指向由“Hello”创建的字符串实例。s2 所指的的对象是以 s1 作为初始化而创建的。因此这两个字符串对象的内容是一样的。但它们是不同的对象,这就意味着 s1 和 s2 没有指向同一的对象,因此它们是不==的。

因此,千万不要使用==运算符测试字符串的相等性,以免在程序中出现糟糕的 bug。从表面上看,这种 bug 很像随机产生的间歇性错误。

对于习惯使用 C++String 类的人来说,在进行相等性检测的时候一定要特别小心。C++String 类重载了==运算符以便检测字符串内容的相等性。可惜 Java 没有采用这种方式,它的字符串“看起来、感觉起来”与数值一样,但进行相等性测试时,其操作方式又类似于指针。语言的设计者本应该像对 C++ 那样也进行特殊处理, 即重定义==运算符。

当然,每一种语言都会存在一些不太一致的地方。C 程序员从不使用==对字符串进行比较,而使用 strcmp 函数。Java 的 compareTo 方法与 strcmp 完全类似。所以下面我们来介绍 Java 的 compareTo 方法。

compareTo() 方法
通常,仅仅知道两个字符串是否相同是不够的。对于排序应用来说,必须知道一个字符串是大于、等于还是小于另一个。一个字符串小于另一个指的是它在字典中先出现。而一个字符串大于另一个指的是它在字典中后出现。字符串(String)的 compareTo() 方法实现了这种功能。

compareTo() 方法用于按字典顺序比较两个字符串的大小,该比较是基于字符串各个字符的 Unicode 值。compareTo() 方法的语法格式如下:

str.compareTo(String otherstr);
它会按字典顺序将 str 表示的字符序列与 otherstr 参数表示的字符序列进行比较。如果按字典顺序 str 位于 otherster 参数之前,比较结果为一个负整数;如果 str 位于 otherstr 之后,比较结果为一个正整数;如果两个字符串相等,则结果为 0。

提示:如果两个字符串调用 equals() 方法返回 true,那么调用 compareTo() 方法会返回 0。

例 3
编写一个简单的 Java 程序,演示 compareTo() 方法比较字符串的用法,以及返回值的区别。代码如下:

public static void main(String[] args) {
    String str = "A";
    String str1 = "a";
    System.out.println("str=" + str);
    System.out.println("str1=" + str1);
    System.out.println("str.compareTo(str1)的结果是:" + str.compareTo(str1));
    System.out.println("str1.compareTo(str)的结果是:" + str1.compareTo(str));
    System.out.println("str1.compareTo('a')的结果是:" + str1.compareTo("a"));
}
上述代码定义了两个字符串“A”和“a”,然后调用 compareTo() 方法进行相互比较。最后一行代码拿“a”与“a”进行比较,由于两个字符串相同比较结果为 0。运行后的输出结果如下:

str = A
str1 = a
str.compareTo(str1)的结果是:-32
str1.compareTo(str)的结果是:32
str1.compareTo('a')的结果是:0

String

string的equals
1. str1 ==  str2 
	用来比较str1变量本身所占内存的值和str2变量本身所占内存的值是否相等
        1>  String str1 = "hello";
            String str2 = "hello";  //str1 和 str2 都指向了匿名对象"hello"
        2>
            String str3 = new String("hello");  //str3 和 str4 很明显指向的是不同的对象
            String str4 = new String("hello");
2.str3.equals(str4)
        1> 是用来比较str1变量本身所占内存的值所指向的对象和str2变量本身
	       
           所占内存的值所指向的对象的内容是否相等
	       也就是说如果str1和str2占用不同的内存,但是这两个不同内存的值是一样的,
	       Stirng.equals()方法也会返回true.

        2> 但是Object中的equals()方法却是返回false,Object类中的Equals方法
	       Object中就含有equals()方法,不过String类重写了Object中的equals()方法
3.内存分配空间:
        1>普通属性:自身所占用的空间在堆(heap)中

        2>局部变量:················栈(stack)··

        3>静态变量、字符串常量······数据段(data segment)
                str1 与str2 在堆中分配,而"hello"这个字符串在数据段中分配,并且在数据段中只有一份"hello"的拷贝,由str1 与str2共用,即str1与str2都存放"hello"的地址,都指向"hello"这个字符串。

        /*
            在JDK 1.8中的运行结果是: 
        -------------------------------
        str1 == str2
        str3 != str4
        str3.equals(str4) == true
        -------------------------------
        */
        我的总结:
        1. String str1 = "hello"; // 数据类型 变量名 = "赋值内容"; 
        2. String str3 = new String("hello"); // 类名 对象名 = new 类名(" ") 
        3. str3.equals(str4) //调用已经改写后的equals方法
String类的常用方法
1.  public char charAt(int index) 返回字符串中第index个字符。
             1>  String str = "hello";
            		char ch = str.charAt(1);
            2> 从零开始,例如上面的结果是'e'
    public int s.length() 返回字符串的长度
    public int indexOf(String str2) 
                1>.返回字符串中出现str的第一个位置
                2>.s1.indexOf(s2),返回s2在s1中的位置
                3>初始值为-1,从零开始计数
                String str = "ABCDEFGHIG";
				System.out.printf("%d\n",str.indexOf("A"));//运行结果:0	
    public int indexOf(String str2,int fromIndex)
                2>str1.indexOf(str2,fromIndex)
                1>返回从fromIndex开始,str中出现str2的第一个位置
                               
    public boolean equalsIgnoreCase(String another)
                比较字符串与another是否一样(忽略大写)
    public String replace(char oldchar,chat newchat)
                在字符串中用newchar字符替换oldchar字符

2.静态重载方法
public static String valueOf()//可将基本类型数据转换为字符串
    举例:public static String valueOf(int i)

StringBuff

StringBuff的由来
1.String类对象一旦创建就不可更改
2.如果经常对字符串内容进行修改,则使用StringBuffer.
3.如果经常对字符串内容进行修改而使用String的话,就会导致即耗空间又耗时间!
    例子:
        String s1=“abasdmasc";
        String
        str2=123";
        String s1=s1+s2;
        删除str1中的字母d
4.StringBuffer对象的内容是可以改变的
5.String类中没有修改字符串的方法,但是StringBuffer类中却有大量修改字符串的方法

StringBuff构造函数
public StringBuffer()
创建一个空的没有任何字符的StringBuffer对象
public StringBuffer(int capacity)
创建一个不带字符,但具有指定初始容量的字符串缓冲区。
public
StringBuffer(String str)
创建一个StringBuffer对象,包含与str对象相同的字符序列
StringBuff举例
public class TestStringBuffer
{
        public static void main(String[] args)
        {
            StringBuffer sb = new StringBuffer();
            sb.append("abc");
            sb.append("123");
            System.out.println("sb = " + sb); //sb = abc123
            sb.insert(3, "--");
            System.out.println("sb = " + sb); //sb = abc--123
            sb.delete(2,6); //把下标从2开始到6-1结束的字符删除
            System.out.println("sb = " + sb); //sb = ab23
            sb.reverse();
            System.out.println("sb = " + sb); //sb = 32ba
            String str = sb.toString();
            System.out.printf("str = " + str); //str = 32ba
        }
}

  • 2
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页

打赏作者

歧萌天下

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值