1.java基本环境与class加载
对应不同的操作系统平台有不同的java虚拟机
jdk>jre>jvm
classpath配置的作用:一个类要用到另一个类到classpath路径中去,在jdk1.5中默认是在当前目录下去查询要运行的.class文件
path:在path去找到运行的javac命令
java_home:配置好后其它软件运行只需要在%JAVA_HOME%/bin,查找到javac与其它的命令
在.java文件中,只能有一个public类。
1.使用命令行的方式
.java文件名如果与主类中的class文件不同,则运行程序步骤是:
1.javac 文件名.java
2.java 主类名
2.使用eclipse中书写java文件
运行.java文件,如果主类没有没有去写public类型,而且主类文件名与.java程序文件名不同,则会出现运行出错,因为eclipse会去找同名的class文件去运行
运行步骤是:
1.javac 文件名.java
2.java 文件名
注意:最先有数据的是方法区
类的加载
程序运行过程是:ClassLoader将其Load到内存中CodeSegment,运行环境找到main方法开始执行,classsLoader的类加载机制是并非一次性加载,需要的时候加载(运行期间动态加载)
如果想要得到class加载时候的详细信息
需要在Aguments的Vm arguments中加载-verbose:class
关于class loader的层次关系(不是继承)
classloader在load class的时候首先找上层loader是不是load过了,如果已经load了,就不会再此load
因此导致安全性是非常好的,自己写的String.class永远没有机会执行(破坏性代码),即如果重写java.lang.String代码自己的写永远无法执行,因为jre已经load过这个class文件了,加不会再加载用户写的java.lang.String文件
java.lang.Class
代表了load到内存中的Class对象
Object的getClass()可以拿到该类对象(等同于类名:.class)
Class的getClassLoader可以拿到装载这个class的ClassLoader
所有的classloader都是从
ClassLoader这个类继承而来
System.out.println(com.gudai.NumTest.class.getClassLoader().getClass().getName());
application classloader中有一个parent引用指向ext class loader而后以此类推
分别得到classloader的名称
得到最开始的classloader
System.out.println(String.class.getClassLoader());
得到当前类的classloader即ApplicationClassLoader
System.out.println(com.gudai.NumTest.class.getClassLoader().getClass().getName());
得到jre下的classloader
System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName());
标识符
命名规则
1.组成:字母下划线,“——”,$,或则数字或字符串
2.以字母,下划线,美元符开头
3.java对大小写敏感,长度无限制,(不能有空格)
常量
整形
浮点型
布尔型
字符型
字符串
类型转换
char c='a';
int b=(int)c;//97
注意:int类型之前的数会转换成对应自己的类型,即char类型范围之内的数字会转换成对应的文字,最大为65535个数,数据类型小的自动转换成数据类型大的
转义字符
使用 "\" 表示
2.对象和类以及数据类型与运算
java中最小的信息单元是bit为(比特位)
java中最小的存储单元是字节
java内存:
data区:存放static方法与static变量
code区(方法区):存放代码地区,此中含有常量池(final类型的数据在此处)
heap区(堆区):new出的对象所存放的地方(new Person())
stack(栈区):变量存放的地方
byte:0 float:0.0F
short:0 double:0.0D;
int:0 boolean false;
long 0L 所有的引用类型是null
java当中数据类型分为两种
1.基本数据类型
4类8种
整形:byte(1个字节),short(2字节),int(4字节),long(8字节);
浮点型:float(4字节),double(8字节)
字符:char(2字节)
布尔:boolean(1字节)
2.引用数据类型
数组,字符串,接口,类
属性与成员变量等价,方法与函数等价
成员变量默认初始化是有初始值的,而局部变量是没有初始化值得
一些运算规则是
byte a=1;//数字的默认的数据类型是int类型,编译器自动检测int变成byte类型
byte a=1,b=2,c;
c=a+b;//int数据类型之前的数据计算会自动转换成int类型进行相加,因此会有错,需要写成int c=a+b;
short g=3+4;//是正确的,常量的优化机制
关于计算机中的编码
java中当中采用的编码是unicode编码(占用两个字节)别称万国表,来至标准化组织
常用的其他码表是
ASCII编码表
GBK:一个字符对应两个字节(计算机中对应的编码表)ps:一个中文的中在GBK中占两个字节,一个英文字符a在GBK占一个字节
UTF-8:一个字符对应三个字节(一个中文字占三个字节,一个英文字符占1个字节)
编码表示将电脑显示的文字与电脑需要的二进制做出一一映射的关系
无论文件设置什么格式的,在jvm中编码格式永远是unicode编码
(即:.class文件保存的是unicode编码)
//得到计算机系统内部的编码
System.out.println(System.getPropert("file.encoding"));
char han = '永';
System.out.format("%x", (short) han);//输出6c38
char han1 = 0x6c38;
System.out.println(han1);//输出永
也就是说,只要我们正确地读入了汉字“永”字,那么它在内存中的表示形式一定是0x6c38,没有其他任何值能替代这个字。
byte[] b;
String str = "测";
//UTF8编码格式下,一个汉字占3字节
b = str.getBytes("UTF-8");
System.out.println("UTF8编码格式下,一个汉字占" + b.length + "字节");
//得到系统默认的编码
System.out.println("默认编码" + System.getProperty("file.encoding") + "编码格式下,一个汉字占" + b.length + "字节");
运算符及一般的运算规则
&:一边是false,运算结果就是false,见了false,就是false(两边都需要运行)
|:一边是true,运算结果就是true,见了true,就是true(两边都需要运行)
^:两边相同为false,不同为true;
!:取反!true=false !false=true;
&&:短路与,一边是false,另一边不运行
||:短路或,一边是true,另一边不运行
++与--的操作是
b=a++;//表示的是b=a,而后a++
b=++a;//表示的是b等于a+1后的值,
System.out.println(a++);//打印的是a的值
System.out.println(++a);打印的是++a的值
命名规则camel
1.类名的首字母小写
2.变量名和方法名的首字母小写
3.运用驼峰标识
类的修饰符
public:表示在任何地方都可以引用此类
default:表示在同一个包中才可以引用此类
absract:表示此类是一个抽象类(ps:抽象类中可以含有抽象方法与非抽象方法)
注意:含有抽象方法的类一定是抽象类
类中成员的修饰符
public:这个类的对象(ps:静态的调用)表示的是该成员在类中,同包中,子类中,任何地方都是可以访问的
protected:表示是该成员在类中,同包中,子类中都是可以访问的
default:表示的是该成员在类中,同包中都是可以访问。
private:表示是该成员在类中是可以访问的
函数(方法):
构造函数:
用构造对象使用,它必须与类名相同,默认添加构造方法:无参构造方法,构造方法无返回值
但是可以有return语句
局部变量
变量的修饰只能是public,default,protected,private
final类型
注意:局部变量不用static关键字去修饰
方法的重载:
是指一个类中可以定义有相同的名字,但是参数不同的多个方法,调用时,会根据不同的参数表选择对应方法。
重载的条件:
1.参数的个数不同
2.参数的类型不同
注意:重载只与方法中的参数有关而与方法的返回值无关
接口(特殊的抽象类):interface
定义:接口是抽象方法和常量值的定义的集合,从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现
是一种特殊的抽象类,使用interface表示声明,抽象方法无需实现。
接口中成员变量默认是:public static final int num=0;(ps:变量也只能是这种类型,这三种修饰符可以相互改变位置)
接口中方法是:public abstract int test();(ps:如不写public,编译通过,运行可能出现错误)
接口中是无构造方法
特性
1.接口可以多重实现
2.接口中声明的属性默认为public static final ;也只能是public static final
3.接口只能定义抽象方法,而且这些方法默认是public abstract的也只能是public的
4.接口可以继承其它的接口,并添加新的属性和抽象方法
注意:
1.多个无关的类可以实现同一个接口
2.一个类可以实现多个无关的接口
3.与继承关系类似,接口与实现类之间存在多态性
类-类 继承 接口--接口 继承 类---接口 实现
内部类:
1.局部类部类
定义在方法中的内部类,如果内部类要使用局部变量必须是这个变量必须是final类型的( ps:因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用)
2.成员类部类
定义在一个类的内部方法外
1.私有的成员内部类
2.静态的成员内部类
3.匿名内部类(一种特殊局部内部类)
定义在一个对象内中,如:
new Thread(new Runner(){
//此处就是一个匿名的内部类(形式:new 接口/类,形成的就是其实现接口的子类或继承类的子类)
//
});
注意:方法调用完成后这个类还是存在的
调用内部类
生成内部类对象:
普通的内部类生成:
内部类 变量名=new 外部类().new 内部类();
静态的成员内部类:
内部类 变量名=new 外部类名.内部类();
调用内部类的普通方法:
内部类对象.内部类中的方法名()
调用内部类的静态方法
内部类名称调用.方法名
方法
可变参数的方法使用:
public static void main(String[] args) {
String str=getNum("zhang","文","cai");
System.out.println(str);
}
public static String getNum(String ... agrs){
String str1="";
for(String str:agrs){
str1+=str;
}
return str1;
}
注意:
1.在方法中基本数据类型转递的数值本身------------将不会改变调用方法中数值
!!!!!!!!!!注意 注意
2.在方法中传递是的引用数据类型是转递的是地址-----将会引用中数据值!!!!!!注意这里传递的是引用地址的拷贝,其实质是按引用地址的按值传递
大多数程序都会犯的错误:其实对象不安引用传递参数
public static void main(String[] args) {
Employee e=new Employee("张三");
Employee e1=new Employee("李四");
swap(e,e1);
System.out.println(e.getName());
}
public static void swap(Employee e,Employee e1){
Employee temp=e;
e=e1;
e1=temp;
//e.setName("张三张三占山");
}
}
class Employee{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Employee(String name) {
this.name=name;
}
构造方法可以
有return;语句
void返回值(空返回值)
可以有return;语句
区块四种
1
{
//构造代码块,优于构造方法先执行
}
2
public void test(){
//方法区块
}
3
static{
//静态代码块,会先执行一次,在构造方法之后
}
4
class Demo{
//类区块
}
注意:所有的在区块中定义的变量不能再,再方块外使用
内存地址只能赋值一次
static关键字
1.在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份
2.用static声明的方法为静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中部可访问非static的成员
3可以通过对象引用或类名访问静态成员
注意:静态方法在data区先加载
访问规则:静态的方法只能有静态成员,
非静态的方法可调用静态成员
局部变量不可用static修改!!!!!!
final关键字
1.final的变量的值不能够被改变
final的成员变量
final的局部变量
2.final方法不能够被重写
3.final的类不能够被继承
各种语句写法
switch(表达式){
case 常量:
执行语句;
break;
}
循环
1. while(){
//break是跳出当前循环,continue是继续下一次循环
}
2. for(int i=0;i<10;i++){
}
3. do{
}while();
注意:jdk1.0-1.4 数据类型接受byte short int char
jdk1.5 数据类型接受byte short int char enum(枚举)
jdk1.7 数据类型接受byte short int char enum(枚举),String
第三 继承与面向对象
this关键字
表示指向当前对象的引用
super关键字
指向当前对象的父类引用
对象的转型
1.一个基类的引用类型变量可以"指向"其子类的对象
2.一个基类的引用不可以访问其子类对象新添加的成员属性和方法
3.可以使用引用变量instanceof类名来判断该引用型变量所指向的对象是否属于该类或该类的子类。
4.子类的对象可以当作基类的对象来使用称向上转型(upcasting)反之称为向下转型
ps:子类对象不可以转换成父类对象!!!!
方法的重写:
1.在子类中可以根据需要对从父类中继承来的方法重写
2.重写方法必须和被重写方法具有相同的方法名称,参数列表和返回类型
3.重写方法不能使用比被重写方法有更严格的的访问权限
继承中构造方法
1.子类的构造的过程中必调用父类的构造方法!!!!
2.子类可以在自己的构造方法中使用super(argument_list)调用基类的构造方法
1.使用this(argument_list)调用本类的另外的构造方法
2.如果调用super必须写在子类构造方法的第一行
3.如果子类的构造方法中没有显示的调用基类的构造方法,则系统默认调用基类无参数的构造方法
多态
是指在执行期间(而非编译期期)判断所引用对等的实际类型,根据其实际的类型调用其相应的方法
实现条件
1.要有继承
2.要有重写
3.父类引用指向子类对象
注意:子类的方法权限必须比父类访问权限大或者相同
父类中静态方法能覆盖子类的静态的方法
子类抛出的异常不能比父类抛出的异常大
第四 异常
异常:程序运行期间出现的错误
异常的分类
Throwable下有error,与Exception类
而exception下又包含RunTimeException
异常的处理与捕获
catch语句
1.在catch语句块中是对异常进行处理的代码,每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象
2.在catch中声明的异常对象(catch (sourceException e))封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息
常用方法:
(1)例如:
getMessage()方法,用来得到有关异常事件的信息
(2)PrintStackTrace()方法,用来跟踪异常事件对象发生的执行
ps:首先捕获范围晓得异常,在捕获范围大的异常
使用自定义异常
使用自定义异常一般步骤如下:
1.通过继承java.lang.Exception类声明自己的异常类
2.在方法适当的位置生成自定义异常的实例,并用throw语句抛出
3.在方法的声明部分用throws语句声明该方法可能抛出的异常
注意:重写方法需要抛出与原方法所抛出异常类型一致的异常或不抛出异常
代码:
clas MyException{
private int id;
public MyException(String message,int id){
super(message);
this.id=id;
}
public int getId(){
return id;
}
}
public class Test{
public void regist(int num) throws MyException{
if(num<0){
throw new MyException("登录失败",3);
}else{
System.out.println("登录成功,登录码="+num);
}
System.out.println("操作结束");
}
public void manager(){
try{
regist(100);
}catch(MyException e){
System.out.println("操作失败");
e.printStackTrace();
}
}
public static void main(String [] agrs){
Test t=new Test();
t.maneger();
}
}
第五 集合与常用类以及包装类及数组
集合又叫容器
1.j2sdk所提供的容器api位于java.util包中
2.容器api的类
(interface)collection------>(interface)set
------>(interface)list
Map<interface>------->HashMap
Collection接口中所定义的方法
boolean add(Object element);//向容器中添加元素
boolean addAll(Collection c);//向另一个容器中添加容器c中所有的元素
void clear();//清空容器
boolean contains(Object element);//容器中是否包含element对象
boolean containsAll(Collection c);//容器中是否包含c中所有的容器元素,包括[]
Iterator iterator();//遍历容器中要使用的
Object[] toArray();//将容器中所有的元素转换成对应的数组
boolean isEmpty();//容器是否为空
boolean remove(Object element);//移出容器的中的元素
boolean removeAll(Collection c);//移除容器中包含容器c中的元素
boolean retainAll(Collection c);//保留和容器c中相同的元素
int size();//容器大小是多大
ps:打印容器会显示
[测试1,测试2]这种字符串
public class TestColllection {
public static void main(String[] args) {
Collection c=new HashSet();
c.add("hello world");
c.size();
c.add(new Name("张","三"));
c.remove(new Name("张","三"));
c.add("测试");
System.out.println(c);
//System.out.println(typeof c);
Collection b=new HashSet();
b.add("测试");
//c.add(b);
//c.toArray();
System.out.println(c);
//c.removeAll(b);
//System.out.println(c.removeAll(b));
System.out.println(c.retainAll(b));
System.out.println(c);
}
}
class Name implements Comparable{
private String firstName;
private String lastName;
public Name(String firstName, String lastName) {
//super();
this.firstName = firstName;
this.lastName = lastName;
}
public boolean equals(Object o){
if(o instanceof Name){
Name name=(Name)o;
return firstName.equals(name.firstName)&&lastName.equals(name.lastName);
}
return super.equals(o);
}
public int hashCode(){
return lastName.hashCode();
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
Name name=(Name)o;
int cmp=firstName.compareTo(name.firstName);
return cmp!=0?cmp:lastName.compareTo(name.lastName);
}
}
ps:这里需要注意一下all再没有加泛型的情况下是可以将一个集合加入另一个集合当中去的,可以使用addAll方式将一个集合中所有元素加入到另一个集合当中去
容器内元素比较相等
容器类对象在调用remove,contains等方法时需要比较对象是否相等,这会涉及到对象类型的equals方法和
hashcode方法;对于自定义的类型,需要重写equals和hashCode方法以实现自定义的对象规则
注意:相等的对象应该具有相等的hash codes
注意:容器与数组不同的是可以放入不同类型的对象
collection接口定义了存取一组对象的方法,其子接口set和list分别定义了存储方式
1.set(接口)中的数据对象没有顺序且不可以重复
HashSet:线程不安全,存取速度快。底层是以哈希表实现的
TreeSet:红-黑树的数据结构,默认对元素进行自然排序。如果在比较的时候两个对象返回值为0,那么元素重复。
set的常用的方法:
add();添加一个集合元素
ps:构造方法用以初始化容器类
//构造方法用以初始化容器类,Set与list容器都具有Constructor(Collection c)
Set sn=new HashSet(s1);//其中s1表示一个set容器的引用
2.list (接口)中的数据对象有顺序且可以重复
ArrayList:数组实现,查找快,增删慢,由于是数组实现,在增上的时候会牵扯到数组增容,以及拷贝元素,所以慢。数组是可以直接按索引查找,所以查找时较快。
LinkedList:链表实现,增删快,查找由于链表实现,增加时只要让前一个元素记住自己就可以,删除时让前一个元素记住后一个元素。这样的增删效率较高但查询时需要一个一个的遍历,所以效率较低。
Vector:和ArrayList原理相同,但是线程安全,效率低
list 常用方法:
void add(int i,E element)//在给定位置添加一个元素
void addAll(int i,Collection <? extends E> elements)//将某个集合中的所有元素添加到给定位置
E remove(int i);//删除给定位置的元素添加到给定位置
E get(int i);//获取给定位置的元素
E set(int i;E element);//用新元素取代给定位置的元素,并返回原来那个元素
int indexOf(Objetc element);//返回与指定元素相等的元素在列表中第一次出现位置,如果没有这样的元素将返回-1.
int lastIndexOf(Object element);//返回与指定元素相等的元素在列表中最后一次出现的位置,如果没有这样的元素将返回-1
collections类
list的方法
类java.util.Collections提供了一些静态方法实现了基于list容器的一些常用算法
Collections.addAll(array,1,2,3,4);
void sort(list) //对List容器内元素排序
void shuffle(List)// 对List容器内的对象进行随机排列
void reverse(List)// 对List容器内的对象进行逆序排列
void fill(List,Obejct)// 用一个特定的对象重写整个list容器
void copy(List dest,List src);//将src list容器内容拷贝到desc list容器
void addAll(list,Integer ...args);//向list中添加元素
int binarySearch(List,Object)//对于顺序的list容器,采用折半查找的方法查找特定对象
3.map接口定义了存储(key)---值(value)映射的方法
map:键值对 键不可重复,值可以重复
HashMap:红-黑树的数据结构,默认都元素进行自然排序(String).如果在比较的时候两个对象返回值为0,那么元素重复
HashTable 底层也是使用了哈希表维护,存取的读取快,存储元素是无序的
Comparable接口
所有可以"排序"的类都实现了java.lang.Comparable接口,Comparable接口中只有一个方法
public int compareTo(Object obj);该方法
返回0 表示this==obj
返回正数表示this>obj
返回负数表示this<obj
注意:容器的对象的类实现了Comparable接口的类通过实现comparaTo方法从而确定该类对象的排序方式
注意:古老的容器,Vector与HashTable实现线程安全是基于Syschronzied实现的,因此效率低
Iterator接口
1.所有实现了Collection接口的容器类都有以恶搞iterator方法用以返回一个实现了Iterator接口的对象
2.Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作
3.Iterator接口定义了如下方法:
boolean hashNext();//判断游标右边是否有元素
Object next();//返回游标右边的元素并将游标移动到下一个位置
void remove();//删除游标左面的元素,在执行完next之后该操作只能执行一次
Map接口
实现Map接口的类用存储键-值对
Map接口的实现类有HashMap和TreeMap等
Map类中存储的键-值对通过来标识,所以键值不能重复
常用的方法
Object put(Object key,Object value);//将元素放入到map中
Object get(Object key);//通过key值得到对应的值
Object remove(Object key);//通过对应的键值删除对应的元素,返回移出所有的元素
boolean containsKey(Object key);//是否包含key值
boolean containsValue(Object value);//是否包含value值
int size();//map大小
boolean isEmpty();//判断的map是否为空
void putAll(Map t);//将t将放入一个map中
void clear();//清楚map,形式是{a="xxx"}
输出map的形式{a=value,b=value}
增强for循环(来至jdk1.5)
优点: 对于遍历array或collection的时候相当简便
缺陷:
数组:
不能方便的访问下标值
集合:
与使用Iterator相比,不能方便的删除集合中的内容
总结:除了简单遍历并读出其中的内容外,不建议使用增强for
遍历容器:
1.遍历list(三种方式):
1.增强for循环
for(String elt:list){
Sysem.out.println(elt);
}
2.下标
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
3.迭代器
for(Iterator<String> iter=list.iterator();iter.hasNext();){
String elt=iter.next();
System.out.println(elt);
}
2.遍历Set
1.增强的for循环
for(String elt:set){
System.out.println(elt);
}
for(Iterator<String> iter=set.i
2.迭代器terator();iter.hasNext();){
String elt=iter.next();
System.out.println(elt);
}
3.遍历Map
1.增强for循环(Entry集合)
for(Entry<String,String> entry:map.entrySet){
System.out.println(entry);
}
//得到的是xx=xx;
2.增强的for循环(key集合)
for(String key:map.keySet()){
System.out.println(key+"="+map.get(key));
}
//得到的是xx=xx
3.遍历值得集合
for(String value:map.values()){
System.out.println(value);
}
map的常用方法
add();//添加一个元素
数组
数组的概述(数组长度是固定的)
1.数组可以看成是多个相同类型数据组合,对这些数据的统一管理。
2.数组变量是引用类型,数组也可以看成是对象。数组中每个元素相当于该对象的成员变量
3.数组中的元素可以是任何数据类型,包括基本数据类型和引用类型
一维数组的声明
1,type var[];或type[] var;
2.int a[];int [] a;
double b[];
3.java语言中声明数组时不能指定其长度(数组中元素的个数)
例如:int a[5];非法
注意:元素为引用数据类型的数组中的每一个元素都需要实例化
数组的初始化
1.动态初始化
数组定义与数组元素的分配空间和赋值的操作分开进行
2.静态初始化
在定义数组的同时就为数组元素分配空间并赋值数组元素的默认初始
String [] str=new String(){"测试1","测试2"}
数组元素的默认初始化
数组是引用类型,它的元素相当于类的成员变量,因此数组分配空间后,每个元素也按照成员变量的规则被隐式的初始化,数组元素的引用。
ps:每个数组都有一个属性length指明它的长度,而字符串是含有一个同名的方法即:str.length();
ps:一维数组的定义方式(三种)---
1. int [] a={1,2,3};//注意:!!!!!此种写法不可写成 int[] a; a={1,2,3};会报错
2. int []a=new int[10];
3. int []b=new int[]{1,2,3}
二维数组(可以看成是数组的数组):
定义时可以是第二空间省略不写
二维数组的创建方式:
1.静态的初始化
int A[][]={{1,2}};
int B[3][2]={{1,2},{2,3},{4,5}};//非法
2.动态初始化
int a[][]=new int[3][4];
数组的拷贝
使用java.lang.System类的静态方法
public static void arraycopy(Object src,int srcpos,Object dest,int destPost,int length)
src源数组名
srcpos源数组起点
dest目标数组
destpost目标数组的起点
int arr[]={1,3,4,5,6,7};
int arrcopy[]=new int[10];
System.arraycopy(arr,1,arrcopy,3,3);
System.out.println(arrcopy[4]);
案例一:
int [][] a=new int[2][];
System.out.println(a[0][1]);
运行结果是:
会报空指针异常,第一个数组中放的是第二数组的引用为null,null访问其内部元素会出现空指针异常
案例二:
int [][] a=new int[2][2];
System.out.println(a[0][1]);//结果是零
Arrays类
使用的静态方法操作的数组:
//其它double char,float类型类似
static String toString(int[] a);//返回指定数组内容字符串表示形式
-----对int类型进行排序-------其它类似
static void sort(int[] a);//对指定的int型数组按数字升序进行排序
static void sort(int[] a,int fromIndex,int toIndex);//对指定int型数组的指定范围按数字升序进行排序
---在a数组中填充val值------其它类型如果double,long,Object..类似
static void fill(int a[],int val);//将指定的int值分配给指定int型数组的每个元素
static void fill(int a[],int fromIndex,int toIndex,int val);//将指定的int值分配给指定int型数组指定范围中每个元素
-------比较连个字符串是否相等----
static boolean equals(int [] a,int[] a2);//如果连个指定的int型数组彼此相等,则返回true
ps:如果两个数组引用都为null,则认为它们是相等的
复制数组:
static int[] copyOfRange(int [] original,int from,int to);//将指定数组的指定范围复制到一个新数组
复制对象数组
static <T> T[] copyOfRange(T[] original,int from,int to);//将指定数组的指定范围复制到一个新数组
复制指定长度的数组:
----基本数据类型
static int[] copyOf(int[] original,int newLength);//复制指定的数组,截取或用0填充(如果必要),以使副本具有指定的长度。
二分法查找:
//在数组范围内查找指定的数
static int binarySearch(int[] a,int key);//使用二分搜索法来搜索指定的int型数组,以获得指定的值
//指定范围获得指定的值
binarySearch(int[] a,int key);//使用二分搜索发来搜索指定的int型数组,以获得指定的值。
String类(final类型的类,因此此类不能被继承):
java.langString类代表不可变的字符序列
"XXXX"为该类的一个对象
String类的常见构造方法
1.String(String origainal)
创建一个String对象为original的拷贝
2.String(char[] value)
用一个字符数组创建一个String对象
3.String(char[] value,int offset,int count)
用一个字符数组从offset项开始的count个字符序列创建一个String对象
String类的常用方法
public char charAt(int index);//返回字符串第index个字符
public int length();//返回字符串的长度
public int indexOf(String str);//返回字符串中出现str的第一个位置
public int indexOf(String str,int fromIndex);//返回字符串中从fromIndex开始出现str的第一个位置
public boolean equalsIgnoreCase(String another);//比较字符串与another是否一样(忽略大小写)
public String replace(char oldChar,char newChar);//在字符串用newChar字符串替换oldChar字符
public boolean startWith(String prefix);//判断字符串是否以prefix字符开头
public boolean endsWith(String suffix);//判断字符串是否以suffix字符串结尾
public String toUpperCase();//返回一个字符串为该字符串的大写形式
public String toLowerCase();//返回一个字符串为该字符串小写形式
public String substring(int beginIndex);//返回该字符串从beginIndex开始到结尾的子字符串
public String substring(int beginIndex,int endIndex);//返回该字符串从beginIndex开
始到endIndex结尾的子字符串
public String trim();//返回将字符串去掉开头和结尾空格后的字符串
**静态方法**
public static String valueOf();//可以将基本类型数据转换为字符串;
如:public static String valueOf(double d);
public static String valueOf(int i);
方法public String[] split(String regex)可以将一个字符串按照指定的分隔符分隔,返回分
隔后的字符串数组
ps:使用toString方法将可变字符串转换成对应的字符串
注意:返回的是一个字符串数组!!!!!
测试代码:
/*char []c=new char[]{'a','b','c'};
String str=new String(c);//通过字符数组创建字符串
System.out.println(str);
String str2=new String(c,1,2);//通过字符数组的1到2的位置创建字符串
System.out.println(str2);*/
String s1="sun java",s2="sun Java";
System.out.println(s1.charAt(1));//u
System.out.println(s2.length());
System.out.println(s1.indexOf("java"));
System.out.println(s1.indexOf("Java"));
System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2));//true
String s3="我是程序员,我在学java";
String str=s3.replace("我","很");
//System.out.println();
System.out.println(str);
String s4="welcome to java world";
String s5=" sun java ";
System.out.println(s4.startsWith("welcome"));
System.out.println(s4.endsWith("world"));
String sl=s4.toLowerCase();
String su=s5.toUpperCase();
System.out.println(sl);
System.out.println(su);
String sp=s1.trim();
System.out.println(sp);
String s6=s4.substring(3);
System.out.println(s6);
int a=12398;
String astr=String.valueOf(a);
//double b=12.33;
System.out.println(astr);
String[] sstr=astr.split("");
System.out.println(sstr[1]);
String str1="张文采";
String str2=str1.substring(1);
System.out.println(str2);
String str3=str1.substring(0,1);
System.out.println(str3);
int u=10;
String st=String.valueOf(10);
System.out.println(st);
案例一:
将一个字符串反向输出,如abc输入而后变成cba输出
String str="abc";
int len=str.length();
char[] c=new char[len];
for(int i=0;i<len;i++){
c[i]=str.charAt(len-1-i);
}
String rstr=new String(c);//返回逆序的字符串
System.out.println(rstr);
案例二:
统计一个字符串中最长的连续字符串如"abcsdfsdj"----则其中最长的是abc;
String s="sdfhaskfjabcdefghijksadkjsfhakjs";
int a;
int b;
List<String> list=new ArrayList<String>();
//int a1='a';
for(int i=0;i<s.length();i++){
b=i;
a=s.charAt(i);
for(int j=i+1;j<s.length();j++){
if(a+1==s.charAt(j)){
a+=1;
}else{
i=j-1;
list.add(s.substring(b,i+1));
break;
}
}
}
System.out.println(list);
注意:
比较两个字符串是否相等,
"张"=="张"//true
new String("张")==new String("张");
new String("张").equals("张");
StringBuffer类
java.lang.StringBuffer代表可变的字符序列
StringBuffer和String类似,但StringBuffer可以对其字符串进行改变
StringBuffer类的常见构造方法:
StringBuffer()
1.创建一个不包含字符序列的"空"的StringBuffer对象
StringBuffer(String str)
2.创建一个StringBuffer对象,包含与String对象str相同的字符序列
StringBuffer常用方法
重载方法public StringBuffer append()可以为该StringBuffer对象添加字符序列,返回添加
后的该StringBuffer对象
public StringBuffer append(String str)
public StringBuffer append(StringBuffer sbuf);
public StringBuffer append(char[] str);
public StringBuffer append(char[] str,int offset,int len)//向字符串中添加从offset开始的len个字符串
public StringBuffer append(double d);
public StringBuffer append(Object obj);
public StringBuffer insert(...)可以为该StringBuffer对象在指定的位置插入字符
序列,返回修改后的该StringBuffer对象引用
public StringBuffer insert(int offset,String str);
public StringBuffer insert(int offset,double d);
public StringBuffer delete(int start,int end);可以删除从start开始到end-1
为止的一段字符序列,返回修改后的该StringBuffer对象引用
//同时含有与String类似的方法
public int indexOf(String str);
public int indexOf(String str,int)
public String substring(int start);
public String substring(int start,int end);
public int length();
特有方法------注意此中String对象中不含有这个方法
public StringBuffer reverse()用于将字符序列逆序,返回修改后的该
StringBuffer对象引用
测试代码:
String str="张文采";
StringBuffer sb=new StringBuffer(str);
StringBuffer sb2=new StringBuffer("zhang");
sb.append("张");
System.out.println(sb);
sb.append(sb2);
System.out.println(sb2);
char[] c=new char[]{'a','b','c','d'};
sb.append(c);
System.out.println(sb);
sb.append(c,2,1);
System.out.println(sb);
sb.append(1.23);
System.out.println(sb);
sb.append(false);
System.out.println(sb);
String st="开始";
sb.insert(0, st);
System.out.println(sb);
sb.insert(0,1.23);
System.out.println(sb);
String str2="this is 张文采";
StringBuffer strbuf=new StringBuffer(str2);
StringBuffer s=strbuf.reverse();
System.out.println(s);
System.out.println("张"=="张");
String s1=new String("张");
String s11=new String("张");
System.out.println(s1.equals(s11));
结果是:
张文采张
zhang
张文采张zhangabcd
张文采张zhangabcdc
张文采张zhangabcdc1.23
张文采张zhangabcdc1.23false
开始张文采张zhangabcdc1.23false
1.23开始张文采张zhangabcdc1.23false
true
true
自动装箱与自动拆箱(自动打包、解包)—-支持在jdk1.5之后
自动将基础类型转换为对象
m1.put("one",1);//将1包装成对象放入map中
自动将对象转换为基础类型
int i=(Integer)m1.get("one");
包装类:
Integer,Double,Character
这些类封装了一个相对应的基本数据类型数值,并为其提供了一系列操作
以java.lang.Integer类为例:构造方法
Integer(int value)
Integer(String s)
Integer的常见方法(包装方法基本相似)
public static final int MAX_VALUE最大的int型数
public static final int MIN_VALUE最小的int型数
public long longValue()返回封装数据的long值
public double doubleValue() 返回封住数据的double型值
public int intValue() 返回封装数据的int型值
public static int parseInt(String s) throws NumberFormatException //将字符串解析
成int型数据,返回该数据
public static Integer valueOf(String s) throws NumberFormatException
返回Integer对象,其中封装的整形数据为字符串s所表示
Math类:
java.lang.Math提供了一系列的静态的方法用于科学计算;其方法的参数和返回值类型一般为double型
abs绝对值
acos,asin,atan,cos,sin,tan
sqrt平方根
pow(double a,double b) a的b次幂
log自然对数
exp e为底指数
max(double a,double b)
min(double a,double b)
random()返回0.0到1.0的随机数
long round(double a) double型的数据a转换为long型(四舍五入)
toDegress(double angrad)弧度->角度
toRadians(double angdeg)角度->弧度
练习
int a=-1;
Math.abs(a);
System.out.println(Math.abs(a));
int b=1;
int c=2;
System.out.println(Math.random());
Random r=new Random();
double d=r.nextDouble();
System.out.println(d);
System.out.println(Math.pow(2, 2));
日期类:
通过创建Calendar类的到当前的是第几月(本身date类中的方法以失效),引入Calendar原因是不同区域时间无法在date类下很好的处理
1.
Date d=rs.getDate("pdate");
Calendar c=Calendar.getInstance();
c.setTime(d);
System.out.println(c.get(Calendar.MONTH));//得到当前的月份
输出:
11
格式日期
Date d=rs.getDate("pdate");
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日");
输出:
2017年12月28日
得到时分秒:
Timestamp ts=rs.getTimestamp("pdate");
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss");
System.out.println(sdf.format(ts));
得到整个详细时间
Timestamp ts=rs.getTimestamp("pdate");
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(ts));
输出:
2006-12-28 10:09:51
三种方式获取当前时间
System.currentTimeMillis();
Date d=new Date();
Calendar c=Calendar.getInstance();
将字符串转换成时间
String s="1970-12-30 08:24:37.0";
Timestamp ts=Timestamp.valueOf(s);//Timestamp是java.sql.*中的
System.out.println(ts);
注意:
java.util.Date是在除了sql语句的情况下使用的。java.sql.Date是针对sql语句使用的,它只包含日期而没有时间部分,它们都有getTime方法返回毫秒数,自然就可以直接构建,后者是在读写数据库的时候用的。
file类
java.io.file类代表系统文件名(路径和文件名)
File类的常见构造方法
public File(String pathname)
以pathname为路径创建File对象,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
public File(String parent,String child)
以parent为父路径,child为子路径创建File对象
File的静态属性String separator存储了当前系统的路径分割符
File类常用方法
通过File对象可以访问文件的属性(全是动态方法)
public boolean canRead()
public boolean canWrite()
public boolean exists();//文件夹是否存在
public boolean isDirectory();//是目录吗
public boolean isFile();//是文件吗?
public boolean isHidden();//是否隐藏
public long lastModified();//最后一次修改,时间
public long length();//文件大小
public String getName();//文件的名称
public String getPath();//文件的路径
通过File对象创建空文件或目录(在该对象所指的文件或目录不存在的情况下)
public boolean createNewFile() throws IOException;//当在f路径下不存在当前路径时,创建文件
public boolean delete();//文件是否删除
public boolean mkdir();//创建单个文件夹
public boolean mkdirs();//创建在路径中的一系列目录
案例一:在类路径下创建文件夹
String separator=File.separator;
String filename="myfile.text";
String directory="mydir1"+separator+"mydir2";
//String directory="mydir1/mydir2";
//String directory="mydir1\\mydir2";这样写会导致在linux中运行不了
File f=new File(directory,filename);
if(f.exists()){
System.out.println("文件名"+f.getAbsolutePath());
System.out.println("文件大小"+f.length());
System.out.println("文件是否可读"+f.canRead());
System.out.println("文件是否可写"+f.canWrite());
System.out.println("文件是否存在"+f.isDirectory());
System.out.println("文件是否可读"+f.isFile());
System.out.println("文件是否隐藏"+f.isHidden());
System.out.println("最后一次修改"+f.lastModified());
System.out.println("文件名称是"+f.getName());
System.out.println("文件路径"+f.getPath());
}else{
f.getParentFile().mkdirs();//在当前类路径下创建文件
}
try{
f.createNewFile();
}catch(IOException e){
e.printStackTrace();
}
Random类
Random r=new Random();
r.nextInt(10);//0到9之间随机数
Scanner类
Scanner sc=new Scanner(System.in);
//如果在进行下一行的输入,在重新书写一遍
int a=sc.nextInt();
枚举
枚举类型
1.只能够取特定值中的一个
2.使用enum关键字
3.是java.lang.Enum类型
public class TestEnum{
public enum Colr={};
}
public class TestColllection {
public enum MyColor{red,green,blue};
public static void main(String[] args) {
MyColor m=MyColor.red;//获取枚举中元素方法
switch(m){
case red:
System.out.println("red");
break;
}
}
}
Object类与java.lang包
可以不需要用import语句直接使用java.lang包中类
java.lang-----包含一些java语言的核心类,如Object、String、Math、Integer、System和Thread,提供常用功能
Object类是所用java类的根基类
String toString方法:
Object类中定义有public String toString()方法,其返回值是String类型,描述当前对
象的有关信息
boolean equals方法:
public boolean equals(Object obj)方法
提供定义对象是否“相等”的逻辑
Object的equals方法定义为:x.equals(y)当x和y是同一个对象的应用时返回true否则返回false
j2sdk提供的一些类,如String,Date等,重写了Object的equals方法,调用这些类的equals方法,x.equals(y),当x和y所引用的对象是同一类对象且属性内容相等时(并不一定是相等对象)
Object clone()方法:
创建并返回此对象的一个副本
int hashCode()
返回该对象的哈希码值
void finalize():
当垃圾回收器确定不存在该对象引用时,由对象的垃圾回收器调用此方法
Class<?> getClass():
返回此Objec的运行时类
Class类
ClassLoader getClassLoader();//返回该类的类加载器
String getName();//以String的形式返回此Class对象所表示的实体(类,接口,数组类,基本类型或void)名称
toString();//将对象转换为字符串
第六 多线程
线程的定义:线程是一个程序内部的顺序控制流
线程和进程的区别
1.每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销
2.线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(pc),线程切换的开销小。
3.多进程:在操作系统中能同时运行多个任务(程序)
4.多线程:在同一个应用程序中有多个顺序流同时执行
java的线程是通过java.lang.Thread类来实现的----其类实现了runnerable接口
VM启动时会有一个由主方法(public static void main(){})所定义的线程
可以通过创建Thread的实例来创建新的线程
每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体
通过调用Thread类的start()方法来启动一个线程
ps:Thread中的构造方法是
Thread();//分配一个新的线程对象
Thread(Runnable target);//通过Runnable接口实现Thread对象
Thread(Runnable target,String name);//分配一个实现Runnable接口名字叫name对象
Thread(String name);//分配一个名字是name的对象
创建线程的两种方式:
1.方式一:继承Thread类
public class TestThread extends Thread{
Thread t=new TestThread();
t.start();
public void run(){
System.out.println("当前线程是"+t.getCurrentName());
}
}
2.方式二:通过实现接口实现
public class TestThread implements Runnable{
TestThread t=new TestThread();
Thread t=new Thread(t);
t.start();
public void run(){
System.out.println("当前线程是"+Thread.getCurrentName());
}
}
线程常用的方法:
isAlive();//判断线程是否还活着
getPrority();//获得线程的优先级数值
setPrority();//设置线程的优先级数值
Thread.sleep();//将当前线程睡眠指定毫秒数
join();//调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,在恢复当前运行-------------------------释放锁
yield();//让出cpu当前线程进入就绪队列等待调度,它告诉当前正在执行的线程把运行机会交给线程池中拥有相同优先级的线程,有可能还是调用此线程--------(注意:它是一个静态的方法)-------------------------------释放锁
其它方法:
static Thread currentThread();//返回对当前正在执行的线程对象引用
long getId();//返回该线程的标识符
String getName();//返回该线程的名称
void interrupt();//向线程发送中断请求。线程的中断状态将被设置为true.如果目前该线程被一个sleep调用阻塞,那么,interruptedException异常被抛出。
static boolean interrrupted();//测试当前线程(即正在执行这一命令)是否被中断。注意,这是一个静态方法。这一调用会产生副作用----它将当前线程中断状态重置为false,即恢复线程的执行状态
以下为Object对象中的方法
wait();//当前线程进入对象wait pool----------------释放锁
notify()/notifyAll();//唤醒此对象的wait pool中的一个/所有的线程------注意此种方法只能在同步代码方法或同步块内部调用。如果当前线程不是对象锁的持有者,该方法抛出IllegalMonitorStateException
sleep/join/yield方法
1.sleep方法
可以调用Thread的静态方法:
public static void sleep(long mills) throws InterruptedException
使得当前线程暂停执行millis毫秒
线程的优先级级别
1.java提供一个线程调度器来监控程序中的启动后进入就绪状态的所有线程,线程调度器按照线程的优先级决定应调度那个线程执行
2.线程的优先级数字表示,范围从1和10,一个线程的缺省优先级是
1.Thread.MIN_PRORITY=1
2.Thread.MAX_PRORITY=10;
3.Thread.NORM_PRORITY=5;
3.使用下述方法获得或设置线程优先级对象优先级
1.int getPriority();
2.void setPriority(int newPriority);//设置的数值在0-10之间,数值越小执行的次数越多
public class TestThread{
public static void main(String[] args) throws InterruptedException{
MyThread myThread=new MyThread();
Thread t1=new Thread(myThread,"t1");
Thread t2=new Thread(myThread,"t2");
t1.start();
t2.start();
}
}
class MyThread extends Thread{
public synchronized void run(){
for(int i=0;i<100;i++){
System.out.println("正在执行----"+i+" "+Thread.currentThread().getName());
if(i==50){
this.notify();
try {
this.wait();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
内部锁------
静态代码块的锁:
将静态方法声明为synchronized也是合法的。如果调用这种方法,该方法获得相关的类对象内部锁。例如,如果Bank类有一个静态同步代码方法,那么当该方法被调用时,Bank.class对象被锁住。因此,没有其他线程可以调用同一个类的这个或任何其他的同步静态方法
内部锁和条件在一些局限。包括:
1.不能中断一个正在试图获得锁的线程。
2.试图获得锁时不能设定超时。
3.每个锁仅有单一的条件,可能是不够的
第七 io流
流:在java程序中,对于数据输入/输出操作以"流"(stream)方式进行;J2SDK提供了各种各样
的"流"类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据
分类
java.io包中定义了多个流类型(类或抽象类)来实现输入输出功能;可以从不同的角度对其进行分类
1.按数据流的方向不同可以分为输入流和输出流
2.按处理数据单位不同可以分为字节流和字符流。
3.按照功能不同可以分为节点流和处理流
j2sdk所提供的所有流类型位于包java.io内都分别继承自以下四种抽象流类型
字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer
节点流:节点流为可以从一个特定的数据源(节点)读写数据(如:文件,内存),用于向程序中输入
数据
处理流:是"连接"在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读
写功能
inputStream-------fileInputStream//节点流
pipedInputStream//节点流
//处理流 filterInputStream----------------------lineNumberInputStream
ByteArrayInputStream //节点流 DataInputStream
SequenceInputStream //处理流 BufferedInputStream
StringBufferInputStream //节点流 PushbackInputStream
ObjectInputStream//处理流
inputStream的基本方法
int read() throws IOException //读取一个字节并以整数的形式返回(int类型),如果返回-1已到输入流的末尾----这里注意一个中文字占2个字节无法使用read()方法读取
int read(byte[] buffer) throws IOException//读取一系例字节并存储到一个数组buffer,返回实际读
取的字节数,如果读取前已到输入流的末尾返回-1
int read(byte[] buffer,int offset,int length) throws IOException//读取length个字节,并存储
到一个字节数组buffer,从length位置开始,返回实际读取的字节数,如果读取前以到输入流的末尾返回-1
void close() throws IOException //关闭流释放内存资源
long skip(long n) throws IOException//跳过n个字节不读,返回实际跳过的字节数
案例:
public static void main(String[] args) {
int b=0;
int count=0;
try {
FileInputStream in=new FileInputStream("E:/a.txt");
try {
while((b=in.read())!=-1){
System.out.println((char)b);
count++;
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println("共读取"+count+"字节数");
}
OutputStream
继承自OutputStream的流是用于程序中输入数据,且数据的单位为字节(8 bit);下图中深色为节点流,浅
色为处理流
OutputStream----------FileOutputStream //节点流
----------PipedOutStream //节点流
-----------FilterOutStream--------------------------DataOutPutStream
-----------ByteArrayOutputStream //节点流 -----BufferedOutputStream
-----PrintStream
---------ObjectOutputStream
构造方法:
OutputStream的基本方法
void write(int b) throws IOException//向输出流中写入一个字节数据,该字节数据为参数b的低8位
void write(byte[] b) throws IOException //将一个字节类型的数组中的数据写入输出流
void write(byte[] b,int off,int len) throws IOException //将一个字节类型的数组中的指定位置(off)开始的,len个字节写入到输出流
void close() throws IOException //关闭流释放内存资源
void flush() throws IOException //将输出流中缓存的数据全部写到目的地
案例一:FileOutputStream使用
FileOutputStream的常用构造方法:
FileOutputStream(String name,boolean append);//创建一个向具有指定name的文件中写入数据的输出文件流。如果第二个参数为true,则将字节写入文件末尾处,而不是写入文件开始处。
public static void main(String[] args) {
int b=0;
FileInputStream in=null;
FileOutputStream out=null;
try{
in=new FileInputStream("E:/a.txt");
out=new FileOutputStream("E:/b.txt");
} catch (FileNotFoundException e){
e.printStackTrace();
}
try{
while((b=in.read())!=-1){
out.write(b);
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Reader
继承自Reader的流都是用于向程序中输入数据,且数据的单位为字符(16bit)
-----BufferedReader-------lineNumberReader//处理流
Reader----- ----CharArrayReader//节点流
-----InputStreamReader(处理流)------FileReader//节点流
-----FilterReader---------PushbackReader //处理流
-----PipedReader//节点流
-----StringReader//节点流
Reader的基本方法
int read() throws IOException //读取一个字符并以整数的形式返回(0~255,如果返回-1已到输入流的末尾---注意返回的数据类型是int类型
int read(char[] cbuf) throws IOException//读取一系列字符并存储到一个数组buffer,返回实际读取的字符数,如果读取前已到输入流的末尾返回-1
int read(char[] cbuf,int offset,int length) throws IOException;//读取length个字符,并存储到一个数组buffer,从offset位置开始,返回实际读取的字符数,如果读取前已到输入流的末尾返回-1
void close() throws IOException//关闭流释放内存资源
long skip(long n) throws IOException //跳过n个字符不读,返回实际跳过的字节数
案例:
public static void main(String[] args) {
FileReader fr=null;
int c=0;
try{
fr=new FileReader("E:/a.txt");
int ln=0;
while((c=fr.read())!=-1){
System.out.println((char)c);
}
fr.close();
}catch(FileNotFoundException e){
System.out.println("找不到指定文件");
}catch(IOException e){
System.out.println("文件读取错误");
}
}
Writer
继承自Writer的流都是用于程序中输入数据,且数据的单位为字符(16bit);下图中深色为节点流,浅色为处理流
---------BufferedWriter //处理流
Writer-----------CharArrayWriter //节点流
----------OutputStreamReader-----FileWriter//节点流
----------FilterWriter //处理流
----------PipedWriter //节点流
----------StringWriter //节点流
-----------FileWriter //处理流
Writer的基本方法
void writer(int c) throws IOException //向输出流中写入一个字符数据,该字节数据为参数b的低16位
void write(char[] cbuf) throws IOException//将一个字符类型的数组中的数据写入到输出流
void write(char[] cbuf,int offset,int length) throws IOException;//将一个字符类型的数组中从指定位置(offset)开始的,length个字符写入到输出流
void write(String string) throws IOException //将一个字符串的字符写入到输出流
void write(String string,int offset,int length) throws IOException//将一个字符串从offset开始的length个字符串写入到输出流
void close() throws IOException//关闭流释放内存资源
void flush() throws IOException //将输出流中缓冲的数据全部写出到目的地
案例:
public static void main(String[] args) {
FileWriter fw=null;
try{
fw=new FileWriter("E:/c.txt");
for(int c=0;c<=50000;c++){
fw.write(c);
}
fw.write("张三张三张三张三张三李四李四李四李四");
fw.close();
}catch(IOException e){
e.printStackTrace();
System.out.println("文件写入错误");
System.exit(-1);
}
}
节点流类型
类型 字符流 字节流
file(文件) FileReader FileInputStream
Memory Array CharArrayReader ByteArrayInputStream
CharArrayWriter ByteArrayOutputStream
Memory String StringReader
StringWriter ----------
Pipe(管道) PipedReader PipedInputStream
PipedWriter PipedOutputStream
处理流类型
处理类型 字符流 字节流
Buffering BufferedReader BufferedInputStream
BufferedWriter BufferedOutputStream
Filtering FilterReader FilterInputStream
FilterWriter FilterOutputStream
Converting
between InputStreamReader 无
bytes and character OutputStreamWriter
Object ------- ObjectInputStream ObjectOutputStream Serialization
Data conversion ----- DataInputStream
DataOutputStream
Counting LineNumberReader LineNumberInputStream
Peeking ahead PushbackReader PushbackInputStream
Printing PrintWrite PrintStream
缓存流(处理流)
缓冲流要"套接"在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法
四种缓冲流,其常用的构造方法为
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)
方法
缓冲输入流支持其父类的mark和reset方法
BufferedReader提供readLine方法用于读取一行字符串(以\r或\n分割)。
BufferedWriter提供了newLine用于写入一个行分隔符
对于输出的缓冲流,写出的数据会现在内存中缓存,使用flush方法将会使用内存中的数据立刻写
出
案例一:
BufferedInputStream流
try {
FileInputStream fis=new FileInputStream("E:/a.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
int c=0;
System.out.println(bis.read());
System.out.println(bis.read());
bis.mark(100);
for(int i=0;i<10&&(c=bis.read())!=-1;i++){
System.out.print((char)c+" ");
}
System.out.println();
bis.reset();
for(int i=0;i<=10&&(c=bis.read())!=-1;i++){
System.out.print((char)c+" ");
}
bis.close();
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
案例二:BufferedReader与BufferedWriter
public static void main(String[] args) {
try{
BufferedWriter bw=new BufferedWriter(new FileWriter("E:/a.txt"));
BufferedReader br=new BufferedReader(new FileReader("E:/a1.txt"));
String s=null;
for(int i=1;i<=100;i++){
s=String.valueOf(Math.random());
bw.write(s);
bw.newLine();
}
bw.flush();
while((s=br.readLine())!=null){
System.out.println(s);
}
bw.close();
br.close();
}catch(IOException e){
e.printStackTrace();
}
}
转换流(处理流)—字节流转换成字符流
!!!!!!!!没有字符流转换成字节流!!!!
InputStreamReader和OutputStreamWriter用于字节数据到字符数据之间的转换
InputStreamReader需要和InputStream"套接"。
OutPutStreamWriter需要和OutputStream"套接"。
转换流在构造时可以指定其编码集合,例如:
InputStream isr=new InputStreamReader(System.in,"ISO8859-1");
案例一:OutStreamWriter转换流
public static void main(String[] args) {
try{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:/a.txt"));
osw.write("测试实时是覅是");
System.out.println(osw.getEncoding());
osw.close();
osw=new OutputStreamWriter(new FileOutputStream("E:/a.txt",true),"ISO8859-1");
osw.write("抽点时间");
System.out.println(osw.getEncoding());
osw.close();
}catch(IOException e){
e.printStackTrace();
}
}
案例二:InputStreamWriter转换流
public static void main(String[] args) {
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
String s=null;
try{
s=br.readLine();
while(s!=null){
if(s.equalsIgnoreCase("exit"))
break;
System.out.println(s.toUpperCase());
s=br.readLine();
}
br.close();
}catch(IOException e){
e.printStackTrace();
}
数据流(处理流)——DataInputStream、DataOutputStream
DataInputStream和DataOutputStream分别继承自InputStream和OutputStream,它属于处理流,需要分别"套接"在InputStream和OutputStream类型的节点流上
DataInputStream和DataOutPutStream提供了可以存取与机器无关的java原始类型的数据(如:int,double等)的方法
DataInputStream和DataOutStream的构造方法为:
DataInputStream(InputStream in)
DataOutputStream(OutputStream out)
常用方法:
java.io.DataInputStream
readBoolean();
readInt();//此输入流的下四个字节,将它们解释为一个int
readDouble();//从包含的输入流中读取此操作需要的字节
readLine();//此输入流中的下一文本行
java.io.DataInputStream
常见方法:
writerUTF();//以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流
writeLong(Long v);//将一个short值以8-byte值形式写入基础输出流中,先写入高字节
ByteArrayOutputStream设置默认缓存区-----创建一个新的byte数组输出流。缓冲区容量最初是32字节
案例:
ByteArrayOutputStream baos=new ByteArayOutputStream();
DataOutputStream dos=new DataOutputStream(baos);
try{
dos.writeDouble(Math.random());
dos.writerBoolean(true);
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
System.out.println(bais.avaiable());
DataInputStream dis=new DataInputStream(bais);
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
dos.close();
dos.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
打印流(处理流Print流)
PrintWriter和PrintStream都属于输出流,分别针对与字符和字节。
PrintWriter和PrintStream提供了重载的print
PrintWriter和PrinStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息
PrintWriter和PrintStream有自动flush功能
常用的方法
PrintWriter(Writer out)
PrintWriter(Writer out,boolean autoFlush)
PrintWriter(OutputStream out)
PrintWriter(OutputStream out,boolean autoFlush)
PrintWriter(OutputStream out)
PrintStream(OutputStream out,booleanautoFlush)
案例
System.out是一个典型PrintStream流
ps:System的常见方法
setOut();//重新分配“标准”输出流
PrintStream ps=null;
try{
FileOutputStream fos=new FileOutputStream("E:/a.txt");
ps=new PrintStream(fos);
}catch(IOException e){
e.printStackTrace();
}
if(ps!=null){
System.setOut(ps);
}
in ln=0;
for(char c=0;c<=60000;c++){
System.out.println(c+" ");
if(ln++>=100){System.out.println();ln=0;}
}
Object流(对象流)
作用是直接将Object写入或读出
transient关键字
serializable接口
externaliable接口
案例:
T t=new T();
FileOutputStream fos=new FileOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(t);
oos.flush();
oos.close();
FileInputStream fis=new FileInputStream();
ObjectInputStream ois=new ObjectIputStream(fis);
T tRead=oos.readObject()
System.out.println(tRead.i);
}
}
class T implemnts Serializable{
int i=10;
int j=9;
double d=2.3;
}
第八 socket
通信协议分层的思想
为什么要分层
由于节点之间联系很复杂,在制定协议时,把复杂层分解成,一些简单的成分,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展
通信协议的分层规定
把用户应用程序作为最高,层,把物理通信线路作为最低层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准
ogi:7层模型 应用层,表示层,会话层,传输层,网络层,数据链路层,物理层
Tcp/Ip参考模型:4层 应用层,传输层,网络层,物理+数据链路层
Tcp协议和UDP协议
TCP是专门设计用于在不可靠的因特网上提供可靠的,端到端的字节流通性的协议。它是一种面向连接的协议。TCP连接是字节流而非报文流。
UDP向应用程序提供了一种发送封住的原始的ip数据报的方法,并且发送时无需建立连接。是一种不可靠的连接
Socket
两个java应用程序可以通过一个双向的网络通信连接实现数据交换,这个双向链路的一端称为socket
Socket通常用来实现client-server连接
java.net包中定义的两个类Socket和ServerSocket,分别用来实现双向连接的client和server端
建立连接时所需的寻址信息为远程计算机的ip地址和端口号
TCP端口 与UDP端口分开
TCP方式:
可靠的
UDP方式:
不可靠的、效率高、数据报/非连接
java.net.socket
构造方法创建:
Socket(); //通过系统默认类型的SocketImpl创建未连接的套接字
Socket(InetAddress host,int port);//创建一个流套接字并将其连接到指定的ip地址的指定端口号
方法:
InputStream getInputStream();//返回此套接字的输入流
java.net.ServerSocket
常见的构造方法:
ServerSocket();//创建非绑定服务器套接字
ServerSocket(int port);//创建绑定到特定端口的服务器套接字
ServerSocket(int port,int )
方法:
accept();//侦听并接受到此套接字的连接
案例一:
Tcp连接的方式:
服务器端:
ServerSocket ss=new ServerSocket(6666);
while(true){
Socket s=ss.accept();
System.out.pirntln("a client connect");
DataInputStream dis=new DataInputStream(s.getInputStream);
System.out.println(dis.readUTF());
dis.close();
s.close();
}
Socket s=new Socket("127.0.0.1",6666);
OutputStream os=s.getOutputStream();
DataOutputStream dos=new DataOutputStream(os);
Thread.sleep(3000);
dos.writerUTF("hello server!");
dos.flush();
dos.close();
s.close();
客户端:
Socket s=new Socket("127.0.0.1",6666);
OutputStream os=s.getOutputStream();
DataOutputStream dos=new DataOutputStream(os);
Thread.sleep(30000);
dos.writeUTF("hello server");
dos.flush();
dos.close();
s.close();
案例二:
java.net.DatagramPacket 类的作用
//数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同顺序到达。不对包投递做出保证
构造方法:
DatagramPacket(byte[] buf,int length,InetAddress address,int port);//构造数据包,用来将长度为length的包发送到指定主机的指定的端口号
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) // 构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
java.net.DatagramSocket//此类表示用来发送和接受数据报包的套接字
构造方法:
DatagramSocket(int port);//创建数据报套接字并将其绑定到本地主机上的指定端口
DatagramSocket(int port,InetAddress laddr);//创建数据包套接字,将其绑定到指定的本地地址
方法:
bind(SocketAddress addr);//将此DatagramSocket绑定到特定的地址和端口
close();//关闭此数据套接字
案例实现之UDP:
服务器端
public static void main(String[] args) throws IOException {
byte buf[]=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
DatagramSocket ds=new DatagramSocket(5678);
while(true){
ds.receive(dp);
ByteArrayInputStream bais=new ByteArrayInputStream(buf);
DataInputStream dis=new DataInputStream(bais);
System.out.println(dis.readUTF());
}
}
客户端:
public static void main(String[] args) throws IOException {
long n=1000L;
ByteArrayOutputStream baos=new ByteArrayOutputStream();
DataOutputStream dos=new DataOutputStream(baos);
dos.writeUTF("张三");
byte[] buf=baos.toByteArray();
System.out.println(buf.length);
DatagramPacket dp=new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",5678));
DatagramSocket ds=new DatagramSocket(9999);
ds.send(dp);
ds.close();
}
第九 泛型(jdk1.5新增)
集合中使用的泛型
当集合中存储的对象类型不同时,那么会导致程序在运行的时候的转型异常,存入的是特定的对象,取出的时候是Object对象,需要强制类型转换,可能诱发类型转换异常.无法控制存入的是什么类型的对象,取出对象的时候进行强转时可能诱发异常,而且在编译时期无法发现问题
所以在jdk1.5后出现了泛型
格式:集合类<类类型> 变量名 = new 集合类<类类型>();
源码详解:
`
jdk5.0之前的comparable:
public interface Comparable{
public int compareTo(Object o);
}
JDK5.0之后的Comparable
public interface Comparable<T>{
public int compareTo(T o);
}
`
使用泛型的注意:
1.声明好泛型之后,集合中只能存放特定类型元素
2.泛型类型必须是引用类型,也就是集合不能存储基本数据类型
3.使用泛型后取出元素的不需要类型转换
方法中使用泛型(函数上的泛型)
解决的问题是:写一个函数,调用者传递什么类型的变量,该函数就返回什么类型的变量
使用泛型解决以上问题:
就是将类型当作变量处理。规范泛型的定义一般是一个大写的任意字母
函数上的泛型定义
当函数中使用了一个不确定的数据类型,那么在函数上就可以进行泛型的定义
public <泛型的声明> 返回值类型 函数名(泛型 变量名){
}
注意:使用泛型方法之前需要进行泛型声明,使用一对尖括号<泛型>,声明的位置在static后返回值类型之前,当一个类中有多个函数声明了泛型,那么该泛型的声明可以声明在类上
泛型类(类上的泛型)
类上的泛型声明
语法:
修饰符 class 类名<泛型>{
}
注意:在泛型类中定义一个静态方法,静态方法不可以使用类中定义的泛型,因为类中的泛型需要在对象初始化时指定具体的类型,而静态优于对象存在。那么类中的静态方法就需要单独进行泛型声明,声明泛型一定要写在static后,返回值类型之前。
泛型类细节:
1.创建对象的时候要指定泛型的具体类型
2.创建对象时可以不指定泛型的具体类型(和创建集合对象一样)。默认是Object.例如我们使用集合存储元素的时候没有使用泛型就是那么参数类型就是Object
3.类上面声明的泛型只能应用于非静态成员函数,如果静态函数需要使用泛型,那么需要在函数上独立声明
4.如果建立对象后指定了泛型的具体类型,那么该对象操作方法时,这些方法只能操作以一种数据类型
5.所以既可以在类上的泛型声明,也可以在同时在该类的方法中声明泛型
ps:注意这种写法
`
//子类指定了具体的类型
class Son extends Father<String>{
}
//子类也需要使用泛型
class Son3<T> extends Father<T>{
}
//错误写法,父类上定义有泛型需要进行处理
class Son2 extends Father<T>{
}
`
泛型接口
`
interface Inter<T> {
void print(T t);
}
//使用接口时明确具体类型。
class MyInter2 implements Inter<String> {
@Override
public void print(String t) {
System.out.println("myprint:" + t);
}
}
`
第十 反射机制
读取文件生成文件的中对象
Class c=Class.forName(str);//会将数据加载到内存中
Class c=c.newInstance();//new一个对象
如果想要获取类中的方法
Method[] methods = c.getMethods();
for(Method m:methods){
System.out.println(m.getName);//获取方法名
}
调用这个方法
Object o=c.newInstance();
for(Method m:methods){
if(m.getName().equals("mm")){
m.invoke(o);//m.invoke(o,1,2);
for(Class paramType:m.getParameterTypes()){
System.out.println(paramType.getName());//得到方法的参数类型
}
}
}
Class returnType=m.getReturnType();
System.out.println(returnType.getName());//得到返回值类型的名称
注意:
public void test(int ...){
//可变参数的方法,即参数可以是一个或是多个
}
第十一 正则表达式(RegularExpressions)
用途:字符串匹配(字符匹配),字符串查找,字符串替换
类:
java.lang.String
java.util.regex.Pattern
java.util.regex.Matcher
java.lang.String
常用方法
matches("...");
replaceAll("\\d","-");
初识 .(表示一个字符) *(零或多个) +(一个或多个) ?(一个或零个)
java当中.用 \. 表示,而正则表达式中表示的是 \\.
一个\ 在java当中表示的是\\
一个\ 在java的正则表达式中表示的是\\\\
//posix style 符合unix上的正则表达式的标准
//p("a".matches("\\p{Lower}"));
//边界匹配
p("hello sir".matches("^h.*"));
p("hello sir".matchs(".*sir$"));
//匹配单词边界(表示的空格与制表符)
p("hello sir".matches("^h[a-z]{1,3}o\\b.*"));
p("hellosir".matches("^h[a-z]{1,3}o\\b.*"));
Pattern p=Pattern.compile("\\d{3,5}");//这个正则字符串
//匹配模板
String s="123-34345-234-00";//这个字符串
Matcher m=p.matcher(s);
//
p(m.find());//找到一个匹配的子串,而后再找去剩下的子串中继续去找
matches()//是匹配所有的字符串
lookingAt()//都是重头上开始找
m.start()//找到子串的起始地位置
m.end()//找到子串的起始地位置
m.group()//查找分配的第一组的子串
字符串的替换
replaceAll();//找到所有的匹配的所有字符串并替换
分组使用——()
符合第一组的大串
m.group(1);//返回分组的全部所有的子串
qulifilers(修订符,限定词)—–默认的写法是贪婪的
greey是跳最多吞与其匹配,不匹配向外吐出一个
?
+ positive匹配之后不向外吐
第十二 代理
静态代理
jdk动态代理
cglib动态代理
第十三 算法
选择排序
public static void chooseSort(int[] arr){
int temp;
for(int i=0;i<arr.length;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
}
冒泡排序
public static void bubbleSort(int[] arr){
int temp=0;
for(int i=0;i<arr.length-1;i++){
for(int j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=arr[j];
}
}
}
}
二分法查找
public static int binarySearch(int[] arr,int key){
//定义三个指针变量
int min=0;
int max=arr.length-1;
int mid=0;
//循环折半,条件min<=max
while(min<=max){
//公式,计算中间索引
mid=(min+max)/2;
//让被找元素,和中间索引元素进行比较
if(key>arr[mid]){
min=mid+1;
}else if(key<arr[mid]){
max=mid-1;
}else{
//找到元素,返回元素索引
return mid;
}
}
return -1;
}
直接插入排序
快速排序
链表
栈
第十四 设计模式
单例
工厂
抽象工厂模式
原型模式
观察者模式
访问者模式
责任链模式
代码
打印菱形
public class Lin {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int i,j,k;
for(i=0;i<5;i++) //控制行
{
for(j=0;j<5-i;j++) //控制空格
System.out.print(" ");
for(k=0;k<2*i-1;k++) //控制*号输出
System.out.print("*");
System.out.print("n");
}
for(i=3;i>0;i--)
{
for(j=0;j<5-i;j++)
System.out.print(" ");
for(k=0;k<2*i-1;k++)
System.out.print("*");
System.out.print("n");
}
}
}