1.使用关键字 this来调用其他本类的构造方法,优点同样是最大限度地代码利用程度,减少程序的维护工作量。
对象开辟的内存图:在对象创建时,circle1先指向堆地址,暂时无值,当初始化r和pi之后,堆的值再指向circle1的栈地址
2.当成员变量和局部变量同名时,用this.成员变量名来修饰成员变量。
构造方法:
(1)方法名与类名一致
(2)不写返回值类型(其实是有返回值,只是不写)
(3)用new关键字调用
(4)系统默认分配无参构造,一旦有自定义构造,则只能使用自定义的构造
(已有自定义构造,系统不再分配无参构造)
3.
(1)基本数据类型传递:
4.封装:
成员变量和成员方法的修饰符:public,protected, 默认,private(权限依次从大到小)
(1).private:只在本类中能直接操作,本包其他类也不能访问。
(2).protected:同包所有类及不同包的
子类可以访问。
(3).默认(不写修饰符):同包类可以访问--->包权限
(4).public:同包及不同包的所以类都可以访问-->整个项目
类修饰符:public 和默认
a.成员方法设置private,只能在类内使用
b.
类的访问:
public和默认
优点:1.隐藏实现细节,使得程序安全
2.对用户而言,简单
5.继承:extends
1,优点:
a.提取公共代码,实现代码共用,节省代码
b.如果需要修改公共代码,只需修改父类,程序维护方便。
2.重写:
(a)被重写的方法在父类中已经定义过
(b)重写要求:1.
方法名和参数列表要相同;发生在父类与子类中 //重载:方法名相同,参数列表不同,发生在同一个类中
2.
重写的方法,访问权限不小于父类方法 父类:private方法a() 子类public 重写方法a() 是可以的
3.
返回值类型和父类的返回值类型相同,或者父类返回值类型的子类
4.
抛出异常类型不大于父类的异常类型的范围()
继承特点:
a.父类不能满足子类要求,子类可以重写父类方法;子类调用时,调用的是子类重写的方法,而不是父类的
b.super.父类方法() //调用父类方法
c.调用子类构造,子类构造会
默认先调用
父类无参构造
class B extends A B b=new B(); ->会先调用A(),再调用B();--> B()相当于B(){
super();//可写可不写,默认调用父类无参}
调用父类有参,则super(a,b)进行显式调用
d.一个类只能继承一个父类,但是可以多层继承;若 C extends B; B extends A ;
C c=new C();会先调用B的无参构造,再调用A的无参构造,最后再执行C的构造
局部变量、子类成员变量、父类成员变量
同名
时
局部变量:
直接写变量名
子类成员变量:
this.变量名
父类成员变量:
super.变量名
避免继承的滥用:继承的语义:is-a,是一种
子类 : 是一种 父类:用继承
e:子类从父类继承哪些内容:
(1).public和protected修饰的成员,同包都能继承;不同包protected不能被继承 super.父类方法 //super.父类属性 都可调用
(2).默认:同包能继承
(3).private成员不能继承
(4)
.构造方法不能被继承,可以被子类调用
f.Object类是所有的类的顶层父类,如果一个类没有显式的继承于一个某个父类,默认继承Object类
Object类里的常用方法:
obj.toString() 没有重写打印的是对象的地址; 重写之后打印对象的属性值
obj.equals() 没有重写比较的是内存地址;重写之后比较的是内容(如String类)
obj.getClass()
obj.wait() //暂停一个线程
obj.notify()
obj.notifyAll() //唤醒一个线程
obj.finalize() //内存回收
一个构造方法不能同时调用this和super();一个有参(
??)构造方法如果调用的是this,也能执行父类构造
//因为都要放在第一个位置
如:A(){} A(int a){this();}
6.super类似this的关键字
值域的隐藏,子类有与父类同名属性,则不调用父类已有的属性(如父类a ,子类也有a,则在子类中this.a就是调用子类的a,super.a调用父类的a;
父类有a,子类没有a,则在子类中this.a和super.a都是指向父类的a)
this:当前对象自身
super:当前对象的直接父类对象;
7.继承条件下static代码块、非静态代码和构造函数的执行顺序
先父类static代码块 -> 子类static代码块 -> 父类非静态代码块->父类构造 ->子类非静态 ->子类构造
8.多态:
要求:
(1).建立在继承的基础上
(2).重写
(3). 父类引用指向子类对象; //B extends A A b=new B();
(4).调用被子类重写的方法
总结:
a.父类引用指向哪个子类对象,则调用的是那个子类对象的方法(重写后的新方法)
b.同一方法(被子类重写的方法),多种状态(不同的子类有不同的实现)
c.父类引用只能调用父类已有的方法,不能调用子类特有的方法
静态的方法不能被子类覆盖,
静态的都不能覆盖,要么全静态,要么全非静态。
A { static m1()} B extends A 则父类中的m1()不能被继承。
优点:
(1).提高代码的灵活性,可扩展性和可维护性
(2).用父类引用做形参,减少方法的重载 getA(父类 a)
(3).以父类作为返回值,得到不同的对象 父类 getA(); //简单工厂模式
9.多态 转型:
(a)
向上转型:把子类引用转成父类引用变量,不能调用子类独有的方法
Father father = new Son();父类指向
子类引用对象会遗失除与父类对象共有的其他方法(子类新的方法在编译时会被遗失)
(b).
向下转型:把父类引用转成子类引用变量,必须强制转型,能调用子类独有方法
Son son=(Son)father; //一般先有向上转型之后,才有向下转型,
应先判断其真实子类型,强转的应与真实对象一致
当对象名代表的真实子类型
和强转的类是继承链关系时,强转不会出错
总结:父类引用可以指向子类对象,子类引用不能指向父类对象
10.
instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例
对象名 instanceof 类名
Actor extends Person Person p=new Actor();
System.
out
.println(p
instanceof
Actor); //true
System.out.println(p instanceof Person); //true
System.out.println(p instanceof Object); //true
System.out.println(p instanceof System); //编译错误,与System无关系
11.抽象:
override:重写,父类已有方法实现,子类重写
implements:实现:父类是抽象方法,还未实现,子类提供实现。
抽象方法,只声明返回的数据类型、方法名称和所需参数,但是没有方法体(由子类来实现)
抽象类:abstract 修饰类、方法,
不能修饰成员变量
abstract 修饰的类,可以被继承;修饰的方法,能被子类继承
final:修饰类、方法、变量;
final 修饰的:类不能被继承;
方法 能被继承,但不能被重写;
修饰基本类型变量,变量的值不能被改变;修饰引用类型变量(如类对象),栈内存的引用变量值(指向堆内存的地址)就不能变;
成员变量的值可以改变;final A a=new A("b"); a.setName("sss");是可以的(即堆内存的值可以改变)
(可以修饰非静态变量)
static:修饰静态变量 static final:静态常量
特点:
(a).类中的抽象方法可以是0个或者多个;
(b).抽象类不能通过new关键字来实例化类(没有具体实例对象的类),可以通过子类来实例化
(c).抽象类不一定有抽象方法,但是有抽象方法的类一定是抽象类。
(d).抽象类中可以有构造方法,但不能声明抽象
(e).抽象类不能用final来修饰,抽象方法不能同时被private、static、final或
native(jni使用)同时修饰。
java 抽象类有构造 为什么不能实例化?
抽象类只在分配了在栈中的引用,
没有分配堆中的内存
, 程序都有一个代码段,在内存中需要占据一定的内存,
而抽象类没有具体的实现方法,无法具体的给它分配内存空间,
12.接口 interface implements
a.接口里面
方法默认是: public abstract
b.接口里的
成员变量默认是:public static final的 静态常量
c.子类 实现 接口 (继承:子类 继承 父类 )
d.类可以继承父类,并同时实现接口
e.同样具有多态的特点,接口类型的引用可以指向实现类的对象。
继承:is-a
接口:has-a 接口,用于实现一种能力
接口可以继承接口,子类需实现所有接口的方法 如 interface A B ;B externds A ; C implement B (
C需都实现B和A的抽象方法)
抽象类:
a.可以有抽象方法和具体方法
b.可以有变量
c.子类必须实现所有抽象方法;子类可以保持抽象方法,但子类要声明为抽象类
d.可以用多态
接口:
a.只有抽象方法
b.只能有静态常量
c.实现类必须实现所有抽象方法;实现类可以保持抽象方法,但子类要声明为抽象类
d.可以用多态
两者区别:
a.抽象类有构造方法,接口没有构造方法
面向对象编程:面向接口编程,运用对台
java类不能多继承,但是对接口有多继承;优点:定义与实现分离,安全 缺点:继承功能变少
13.多态(运行时多态):
1.继承:具体类 父类 指向子类
抽象类 父类指向 子类对象
2.接口:接口类引用 指向 实现类对象
3.父类A:
B extends A C extends B ->A a=new C();//继承链可以用多态
4.编译时多态:重载
14.内部比较器:
Compare c1=new Compare(10,20);
Compare c2=new Compare(20,10);
c1.compareTo(c2);
public
int
compareTo(Compare compare){
int result;
if
(
this.length
>compare.
length
){ //
this.length等价于
c1.length
result=1;
}
return result; //String类型比较"a".compareTo("b") 根据unicode编码比较
}
通用型compareTo(Object obj),因为Object是所有类的顶层父类。
public Object[] compareTo(Object[] arr) { //内部比较器
Cat cat[]=(Cat[])arr; //需要强转
int tmp;
for(int i=0;i<cat.length;i++){
for(int j=0;j<cat.length-i-1;j++){
if(cat[j].age>cat[j+1].age){
tmp=cat[j].age;
cat[j].age=cat[j+1].age;
cat[j+1].age=tmp;
}
}
}
return cat;
}
对象数组内存分配:
15.外部比较器:
1.由外部类进行对比较类进行分别比较,可以写多个比较在一个比较类中。
public static void CompareArray(Comp obj,Object arr[]){ //Comp外部比较类实现的接口
Object temp=null;
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr.length-i-1;j++){
if(obj.compare(arr[j], arr[j+1])>0){ //Comp实现类的方法
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
16.成员内部类:
1.成员内部类是类的成员,可以有四种访问修饰符。public 默认 protected private;外部类的访问修饰符 只能默认和public
2.是类的成员,因此内部类的对象要依附于外部类的对象(要调用内部类对象,由外部类对象去调用)
Outer out=new Outer();
Outter.Inner in=out.new Inner();-->或者:Outer.Inner in=new Outer().new Inner();
out
.Inner
iner
=out.new Inner();//错误,理解为out生成时,其他成员已经生成,但是Inner对象还未完成实例化
class Outer{
public class Inner{
void show();
}
}
3.
内部类可以直接访问外部类成员;外部类要访问内部类成员,需创建内部类的对象。
4.外部类成员变量、内部类成员变量、内部类局部变量重名时以下调用方式:编译:Outter.class Outter$Inner.class
public class Outter extends A{
public static int age=10;
public int length=10;
public void print(){
Inner inner=new Inner();
System.out.println("外部类"+inner.age);
}
public class Inner extends B{
private int age=20;
{
printA
(); //代码块
printB
();
}
public void print(){
int age=30;
System.out.println("局部变量"+age);
System.out.println("内部类成员:"+this.age);
System.out.println("外部类成员"+Outter.this.age);
}
}
}
class A{
void
printA
(){
System.out.println("A");
}
}
class B{
void
printB
(){
System.out.println("B");
}
}
内部类优点:
1.可以得到private更小的作用范围;
2.内部类的private成员只在内部类里可以直接访问
3.可以调用A的方法,也可以调用B的方法,变相的实现多继承
17.静态内部类:是一种特殊的成员内部类(staic)
(1).同静态方法一样,不能访问外部类非静态成员。
(2).静态内部类不用生成外部类对象
Outer.Inner in=new Outter.Inner();//???
public static class Inner{
18.方法内部类: 建立在方法里,而不是在类中
1.同局部变量类似,方法内部类不能使用访问修饰符
2.同局部变量类似,方法内部类只能在方法里创建对象。
3.在方法内部类里,如要访问方法的局部变量,则这个变量必须为final类型(出于安全性考虑);
jdk 1.8可以不声明为final,但是内部数值还是不能改变。
class B{
void
printB(){
final int b=10;
class D{
void showD(){
System.out.println("方法中获取的b:"+b);
}
}
D d=new D().showD()
;
}
19.匿名内部类:
1.类只用一次,类里代码不重复使用,不起名字
2.看作是特殊的方法内部类。
3.匿名内部类可以实现一个接口,也可以继承一个抽象类。
4.匿名内部类一次只能实现一个接口,或者继承一个抽象类
5.匿名内部类必须实现所有抽象方法,不能再是抽象类
6.匿名内部类没有构造方法,因为无名字
7.如需要初始化,采用代码块。
8.匿名内部类实质是匿名子对象,如果访问局部变量,局部变量还是要加final。(jdk 1.8除外)
NoaInterface intface=new
NoaInterface
(){ //
NoaInterface为一个接口或抽象类
@Override
public void showInterface() {
System.out.println("NoInterface");
}
};
intface.showInterface();
20.垃圾回收机制:
1.由JRE对不使用的内存进行回收(GC),只回收JVM堆内存的空间
2.将引用变量设置null,或者System.gc()或Runtime.getRuntime.gc()通知系统进行垃圾回收,是否执行由系统决定。
3.在垃圾回收机制回收垃圾之前,总是先调用finalize方法(Object里的方法)
21.异常:在程序运行过程中所发生的不正常事件,会中断程序的运行。
1.例子:String s=null; -->
s.equals("abc"); //会报空指针异常 如使用concat()方法
推荐使用:"abc".equals(s);
2.语法:try{....}catch(Exception e){....}
try{....}catch(Exception e){.....}finally{....}
catch 块:
如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块
(异常类型一致时,执行对应的catch块)
,不会再执行其他的 catch代码块,多重catch,从上到下依次执行catch语句块,执行完跳出try{...}catch{...}语句块,继续执行后续代码。
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。
当在try块或catch块中遇到return语句时,finally语句块将在return
方法返回之前被执行
。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常,或者finally再抛出一个未处理的异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
throws关键字将异常抛给调用者后,如果
调用者
不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的
调用者。
catch块不能单独使用,必须始终与try块一起;finally可以单独使用,不是必须与try一起
3.提示友好信息,可以让程序继续运行。
Error(错误):
是程序无法处理的错误,表示运行应用程序中较严重问题。
Exception(异常):
程序抛出和处理的非严重错误。
异常
分为:
可查异常(编译器要求必须处置的异常):
正确的程序在运行中,很容易出现的、情理可容的异常状况,SQLException和FileNoFoundException、EOFException和
Exception
等
不可查异常(编译器不要求强制处置的异常):
包括运行时异常(RuntimeException
与其子类
)和错误(Error)
运行时异常:
Java编译器不会检查它,也就是说,当程序中可能出现这类异常,
即使没有用try-catch语句捕获
它,也没有用throws子句声明抛
出它,也会编译通过。(不要求程序必须做出处理)
ArithmeticException类和ArrayIndexOutOfBoundsException类都是
RuntimeException
的子类。因此,
RuntimeException(系统不要求程序必须作出处理
)异常类的catch子句应该放在 最后面,
否则可能会屏蔽其后的特定异常处理或引起编译错误。
异常两种抛出方式:1.系统自动抛出异常
2.手动抛出异常,关键字throw
throw 运行时异常,系统不会检查;但是throw可查异常,需要手动作出处理。
如:throw new RuntimeException(不检查) 但是throw new Exception(要求处理)
throw和throws:
throw:抛出一个异常对象,用在方法里;手动抛出异常
throws:(1)异常类型,类名;在方法上声异常,独立进行;
声明异常不同,不是重载的依据
重写:如果是checked异常,子类是父类的异常类型的子类
(2)如果是运行时异常,调用时就不用处理;但若为检查异常,则需要处理。
(3)如果父类方法抛出异常,则子类重写是必须处理;但是子类可以不声明任何异常。
(4)子类:抛出ArithmeticException 父类:抛出Exception() //报错,异常不兼容
ArithmeticException RuntimeException //正常,是同一运行时异常
继承条件下,关注父类和子类的checked异常
自定义异常:如果是继承运行时异常,则系统不会检查异常。
(5).父类没有声明异常,子类throw了一个异常,则子类只能用try{...}catch{...}进行捕获
(6).子类throws的数量比父类多,只要是父类的子异常,不报错。
21.常用工具类:
1.包装类(Wrapper):对基本数据类型而言
基本数据类型不是对象,不能调用方法和属性;为了让基本数据类型当做对象,来调用方法和属性,所有产生包装类。
Integer a=new Integer("abc"); //字符串类型的构造,如果
字符串不是数字格式
,会有NumberFormatException
Java.util.concurrent中实现的原子操作类包括:
AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。 //由硬件提供院子操作指令实现。
优点:开销小,速度快,
在线程内部使用,能
应对高并发处理,保障线程安全。
incrementAndGet()自增方法
decrementAndGet()自减方法
包装类特点:
(1).自动装箱:如Integer
a=15等价于Integer a2=new Integer("15"); //自动把基本数据类型转换成对象。
(2).自动拆箱: 如int b=10; int c=
a+b; //自动将a对象转成基本数据类型,参与运算
int d=new Integer("12");
3.字符串是一个引用类型:字符串本质是由字符数组构成。String中重写了equals()方法,比较的是内容。
str="a"常量值时可以用str=="aa" 比较
str.indexOf() //有存在,则返回对应的索引(相当于字符数组下标);没有返回-1,多个返回第一个
str.charAt(10) //跟索引 str.substring(5) //从5开始,截取字符串
lastIndexof("l",6): 到第7个位置,最右一个l出现的位置。
startWith("aa") 以aa开头的字符串,有大小写之分
trim() 删除头和尾的空格
split("a"); 以a为拆分点,拆分字符串
* 不用新开内存,使用旧的内存,不断扩展新的字符串
StringBuffer: 效率低,安全性高
jdk1.0 一个空的buffer的sb.length()为0,初始容量sb.capacity()为16
StringBuffer sb=new StringBuffer();
StringBuffer sb2=new StringBuffer("Hello"); //长度为5,容量16+5
sb.append("aa") //追加字符串,类似String中的concat();
sb.delete(0,5); //删除索引0-4的字符串,包括头,不包含尾
sb.insert(5,"aa") //从第6个位置,插入字符串aa
StringBuilder:
jdk1.5 效率高,安全性低
equals只比是否相同,compareTo();给出返回值,表示大、小或相等
//abcd引用自常量池
22.日期:
“YYYY/MM/dd --HH:mm:ss--SS” //格式化: 年月日 时 分 秒 毫秒
SimpleDateFormat实现DateFormat(抽象类)
格式化:new Date();
new 格式化器;格式化器的参数,
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
sdf.parse();//格式化时,参数类型要与SimpleDateForma t一致,否则会报错。
日历:Calendar 抽象类 GregorianCalendar()子类
Calendar cal=new GregorianCalendar(); //
Calendar cal2=Calendar.getInstance();
cal.get(Calendar.YEAR) //获取年份的字符串
cal.set(Calendar.DATE,1) //设置成本月第一天
cal.getMaximum(Cal.DATE) //获取本月最大天数
cal.setTime(date) //修改当前系统日期
23.File:
不能修改文件,需通过IO流才能进行文件输入输出操作。
文件:File f=new File("
d:\\a1"); 或者 new File("
d:/a1"); 两种文件路径方式
f.exist() //文件是否存在 f.
mkdir() //创建单层目录(已有,不再创建) f.
mkdirs() //创建多层目录,带有子目录 f.isDirectory() //是否为一个目录
f.delete() //删除文件 f.getName() //获取文件名字 f.getAbsolutePath() //获取绝对路径 如
d:\a1
File
f1
=
new
File(
"d://a1"
); //f1指向a1对象,d://只是文件需要的路径属性
File f=new File("d://a1//a.txt");
f1
.mkdir();//
多层目录下创建文件,需要先创建目录,再创建文件,否则会报找不到指定路径(IOException)。
f.createNewFile()
String fList[]= file.list() //获取文件的名称字符串数组
File fileList[]=file.listFiles(); //获取文件对象存放在文件类型的数组
24.枚举类型(数据集,只能使用固定的一组值):
可以有自己的属性、方法和构造方法
优点:只能取特定值中的一个,不能是数字;需要定义一组常量的时候,使用
public
enum
Sex {
男,女;
} //男女不加引号,枚举的值是
public static final
,可以用枚举名直接调用
使用:private Sex msex; //Sex 枚举名 msex 枚举变量名
setSex(
Gender.男); //直接
枚举类名.属性名调用
switch(
n) //
n可以是枚举类型
Sex
sex
=Sex.女;
switch
(
sex
){
case 女:
System.out.println("女");
break;
25.Math
Math.ceil(3.2) //向上得到最接近的数,4 Math.floor(3.2); //向下得到最接近的数 3
Math.round(3.4) //四舍五入 3
引用:
1.让程序员通过代码的方式决定某些对象的生命周期;2.有利于JVM进行垃圾回收
(1).强引用:
如:Object obj=new Object(); //两者都是强引用,
只要某个对象有强引用与之关联,JVM必定不会回收这个对象,
String str="kkkkk"; //即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象
//
想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null
(2).软引用:
描述一些有用但并不是必需的对象,
java.lang.ref.SoftReference类来表示。
Android开发中对于大量图片下载会经常用到
对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。
很适合用来实现缓存:比如网页缓存、图片缓存等。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,
这个软引用就会被加入到与之关联的引用队列中。
如: SoftReference<String> sr = new SoftReference<String>(new String("hello")); System.out.println(sr.get());
(3).弱引用:描述有用但非必须的对象,java.lang.ref.WeakReference类
当JVM进行垃圾回收的时候,无论内存是否充足,都会回收被弱引用关联的对象。
但如果对象同时被强引用关联的话,就回收不了该对象。
也可以配合一个引用队列(ReferenceQueue)使用,如果弱引用所引用的对象被JVM回收,
则这弱引用会被加入到与之关联的引用队列中
WeakReference<String> sr = new WeakReference<String>(new String("hello")); System.out.println(sr.get()); System.gc(); //通知JVM的gc进行垃圾回收 System.out.println(sr.get());
(4).虚引用:虚引用和前面的软引用、弱引用不同,它
并不影响对象的生命周期。PhantomReference
如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。
虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,
就会把这个虚引用加入到与之 关联的引用队列中。
ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue); System.out.println(pr.get());
26.集合:不知道程序运行时需要哪些对象
(1).集合类:把一些对象存放在一起。
实线边框
的是
实现类
,比如ArrayList,LinkedList,HashMap等,
折线边框
的是
抽象类
,比如AbstractCollection,AbstractList,AbstractMap等,而
点线边框
的是
接口
,比如Collection,Iterator,List等
Collection:集合框架的根接口:无序,不唯一;
List:子接口:有序的,不唯一(可以重复)
Set:子接口:无序的,唯一
数组:基本数据类型,引用数据类型,数组的数据类型与其声明相同。
集合: 接收Object参数
只能存放引用数据类型,加入集合后全部转成Object类型。
如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList: 内存分配连续的空间
优点:遍历元素和随机访问效率高
缺点:添加和删除元素需大量移动元素,效率低,按内容查询效率低
LinkedList: 以链表形式组成
优点:插入、删除效率较高
缺点:遍历和访问元素效率低
Arraylist list=new ArrayList(); //相对于数组优势:容量自动增长,可变长数组,
有索引的方法都在list中
list.add(123); //等价于 Object obj=new Integer(123);
list.add(p); //Person p=new Person();
list.add(1,"kkk") //在第二个元素位置插入
list2.add(999);
list.
addAll(
list2); //对于list2时 以
元素形式,加入集合
list.add(list2); //对于list2时 以
对象形式,加入集合
for(
Object o:list) //多态遍历
删:
remove(p); //多个,删第一个
remove(index); //索引删
remove(
list2) //删除与list2中相同的元素,不止list2中的元素,在removeAll之前才算。
改:
set(index,ele) //在指定索引改元素
List sub=subList(fromIndex,endIndex);// 截取子list,包含from,不包含end
查:
size() //实际元素个数
get(0) //ArrayList有索引,但与数组使用索引不同
contains(Object o) //返回boolean,
list
.contains(Color.
红
) //
Color.
红枚举类型
containsAll()
isEmpty()
IndexOf(c) //查找位置
list.retainAll(list2) //在list中保留所有
list与list2里相同的元素,元素个数有改变
三种遍历方式:
for(
Object o:list) //得到的list集合内元素都是Object
for(int i=0;i<list.size();i++) //有索引的可以,如List
Iterator it=list.iterator();
while(it.hasNext()){ it.next() }
for-each{} 底层也是调用Iterator
迭代器:hasNext() 指向list前方
next() 返回当前迭代器的下一个对象,同时指向当前对象的下一个对象。
remove()
在使用迭代器遍历x时,不能对list再进行增加操作,否则会报错。如果实在需要增加或修改元素时,使用ListIterator进行操作。
LinkList:类似Arraylist上面方法基本都有
addFirst(p) addLast(p) 链尾 //增加头 加尾
offerFirst(p1)
offerLast(p1) //jdk1.6以后新增
getFirst() getLast() //查头 查尾
peekFirst() peekLast()
removeFirst() removeLast() //删头删尾
pollFirst() pollLast()
Set:无序,唯一:
不存在get()
HashSet:无序,唯一(哈希表保证其唯一性,
自定义类要重写hashcode()和equals()),
hashcode相同,equals()不一定是true;
hashcode不同,equals()是false;
equals相同,hashcode一定相同。
里面不能存放重复元素,采用散列的存储方法,没有顺序;
Set: Set set=new HashSet();
set.add(p);
set.remove(p); set.removeAll()
set.retainAll() //取交集
set.contains(p) //boolean
set.containsAll(collection)
TreeSet:
实现了SortedSet接口,能够对集合中的对象进行排序
有序(升序,二叉树排序),唯一;查询速度比List快(按内容比);查询速度比HashSet慢
TreeSet ts=new TreeSet();
(1).自定义类,要实现Comparable接口,实现compareTo()来进行比较。否则不知道比较策略,报Comparable异常
addAll() 根据所实现的compareTo()方法来进行过滤重复字段值。
(2).应用外部比较器,Wcomparatot wc=new Wcomparator(); //自定义外部比较器
TreeSet ts=new TreeSet(wc);
Map:存储键值对的对象,key与value
key:无序,唯一;key不能重复(重复时,会把之前的key覆盖);
key可以为null,只有一个会存在
value:无序,不唯一;可以为null
如果
key为null,则无法迭代得到其对应的value值;对象作为key,则打印该key是显示其对象的值。自动排序
HashMap: Map map=new HashMap();
//如果Map中key是自定义类;别忘了重写hashCode()和equals(),以作对象区别。
map.put("a","aaa");
Set keySet=map.
keySet(); 或者用entrySet() //先将key值提取成一个Set,然后遍历Set
Iterator it=keySet.iterator();
while(it.hasNext()){
map.get(it.next()) } //获取value值如aaa
it.next()只能获取key(a)
remove(key); //删除元素
clear(); //清除元素
containsKey(key) containsValue(value) //查
集合泛型:
集合是对数组做的封装,所以,数组永远比任何一个集合要快
解决数据类型操作不统一而产生的异常,使用泛型限制数据类型,避免强转类型,保障数据安全。
未加特定泛型,默认是Object;
1. ArrayList
<Dog> d=new ArrayList<Dog>(); //加过泛型之后,只能接受Dog对象,数据统一。
Iterator<Dog> it =d.iterator(); //取出的都为Dog的对象了;不用强转。
for
(Map.Entry<String, String> entry : hashMap.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
2.Map
<Dog,String>
m1=
new HashMap<Dog,String>(); //map泛型
Map<Integer,String> m2=new HashMap<Integer,String>();
Set keySet=m2.
keySet(); //
keySet
()获取关键字key的集合
Iterator<Integer> it=keySet.iterator();
//可以Iterator<Integer>或者
Iterator<String>
Set<Entry<Integer, String>>
keySet=m1.entrySet(); //entry<Integer,String>打印整个键值。
Iterator<Entry<Integer,String>>
it=keySet.iterator();
自定义泛型:class Stuent<
T>{ void show(T t) } 使用时就要对其进行泛型; T只是一个指代,可以为a,b,c..
Student<Song> tsong=new Student(); tsong.show(
new Song());
A<String,Integer> t=null; //两个泛型类型的对象 //Key为String,Value为Integer
t.setKey("张三"); t.setValue(10);
优点:避免方法的大量重载;
Dog<Integer,Cat> d =
new Dog<Integer,Cat>(); //存放Integer和Cat的对象
Dog<Integer,Cat> d2 =new Dog<Integer,Cat>();
Dog<Integer,Cat> d3 =new Dog<Integer,Cat>();
Dog dd[]={d,d2,d3};
在Dog类中需加上泛型。
Collection:集合根节点
Collections:集合工具类
Collection.sort(list); //元素中的自定义类,要实现comparable才能排序,否则会出现类似TreeSet排序时的异常;不理会重复
binarySearch(list); //返回索引,不存在返回
-(i+1)
reverse(list) //反转,不一定排序的
Arrays:
静态导入:import static java.lang.Matc.*;
Vector是线程安全的;ArrayList不是
Stack:是Vector的子类,List的实现类,先进后出;
Queue:继承Collection接口,先进先出;
集合和数组区别:
1.数组能存放基本类型和对象,而集合类只能存放对象。
2.数据固定无法动态改变,集合类的容量能动态改变。
3.数组无法判断其中实际存有多少元素,length只能得到数组的容量,而集合的size()可以确切知道元素的个数。
4.集合有多种实现方式和不同使用场合,不像数组仅采用顺序表方式。
5.集合以类形式存在,具有封装、继承、多态等的特性,通过简单的方法和属性即可实现各种复杂操作,提高软件开发的效率。
Vector和ArrayList区别:
1.实现原理相同,功能相同,都是长度可变的数组结构,大多数情况下能互用。
2.ArrayList是Vector的替代接口;Vector线程安全,速度比较慢;ArrayList速度快,线程不安全。
3.长度需要增长时,Vector默认增长一倍,ArrayList增长50%
HashMap和Hashtable区别:
1.实现原理相同,功能相同,底层都是哈希表结构,查询速度快,大多数情况下能互用。
2.HashMap是新接口;Hashtable继承Dictionary类,HashMap实现Map接口
3.Hashtable是线程安全,HashMap线程不安全。
4.Hashtable不允许null值,HashMap允许null值。
27.IO流: 节点流(InputStream等)和处理流(InputStreamReader)
InputStream:从外部数据源文件读到程序内存; OutputStrem:从程序内存中写数据到目的文件;
OutputStream out=new FileOutputStream("d:\\a.txt",true); //有true为追加文件之后,d:\\a.txt文件内容不会被清空;
OutputStream out=new FileOutputStream("d:\\a.txt");
//没有true,文件会被重写,旧的数据会被清空。
源码打开文件,open(name,append) ///append为boolean代表为true,追加不重写旧文件;false重写,旧文件会被重写,内容清空。
字符类和字节流区别:
1.读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
处理对象不同:字节流能处理所有类型的数据(如图片、视频等),而字符流只能处理字符类型的数据(一般为文本类数据)
结论:只要是处理文本数据,优先考虑使用字符流;除此之类优先考虑字节流。
节点流:从
RandomAccessFile 随机存取文件类。
1.不属于流体系,但封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部指针来操作字符数组中的数组。
特点:
a.该对象只能操作文件,构造函数只接受两种类型的参数:a.字符串文件路径 b.File对象
b.该对象能对文件进行读、写操作,并能指定具体的操作模式(r,rw);
c.该对象在创建时候,若文件不存在,则会自动创建;若文件存在,未指定写的位置,会从头开始写(覆盖原来的内容)。
可以用于多线程下载或多个线程同时写数据到文件。
字节流:操作图片压缩文件时常用
InputStream is=new FileInputStream("d:\\a.txt"); //InputStream 字节输入流
is.read() //文件结尾返回-1,读取首个字节;read()有指针,标记每次读到的位置。
//在输入数据可用、检测到流末尾或者抛出异常前,此方法一直
阻塞。
is.read(byte[]) //返回值为每次读取到数组的字节个数,没有则返回-1;汉字占两个字节,byte[n] n需为偶数
while
((n=in.read(readArr))!=-1){
str=new String(
readArr
,0,n); //n为实际元素个数
readArr为byte[] byte[]中的0在String中作为空格符
}
is.available() 获取最大可读字符数
out.write(‘我’); //无法写入到文件中,中文两个字节,会出现乱码
out.flush() //
刷新缓冲区;若没写,在close()时也会刷新缓冲区。
字符流:操作文档时常用
Reader reader=new FileReader(file); //Reader 抽象类 FileReader 子类
reader.read() //返回一个
字符编码代表的整数,无数据仍返回-1
Writer writer=new FileWriter(file,
true); //同样可以追加内容
writer.write('我'); //可以写入,一次写入一个字符
char[] arr={'打',‘请’}; //write(arr) 接收外部数据时使用
字节流到字符流的转换://处理流可以指定编码
InputStream in=new FileInputStream("d:\\a.txt");
InputStreamReader isr=new InputStreamReader(in); //包装inputStream成为InputStreamReader,不能直接用Reader来转。
BufferedReader br=new BufferedReader(isr); //将字符转换流,再包装一次。
OutputStream os=new FileOutputStream("d:\\bb.txt");
OutputStreamWriter osw=new OutputStreamWriter(os,"gbk"); //包装字节输出流; 写入时加\n可以进行换行操作
PrintWriter pr=
new
PrintWriter(socket.getOutputStream(),
true
);
pr.println("aaaaa"
) //接收方为BufferedReader时要用此方法,因为readLine()方法的特点。
字符缓冲流:读写效率高,访问硬盘次数少
Reader
reader=new FileReader("d:\\a.txt");
BufferedReader br=new BufferedReader(
reader); //可以使用nextLine()
Writer
writer=new FileWriter("d:\\bb.txt");
BufferedWriter bw=new BufferedWriter(
writer);
//newLine() 换行
bw
.write(str);
bw.write("\n");
等价于br.newLine() //由于bufferedReader读数据时采用readLine(),加'\n'可以进行提醒读取完毕。
bw
.flush(); //最好写上,不然有可能会出现数据没有正常写入,停留在缓冲区中
字节缓冲流:
BufferedInputStream
bin
=
new
BufferedInputStream(
new
FileInputStream(
testPath
));
BufferedOutputStream bout=
new BufferedOutputStream(
new FileOutputStream(
writePath));
流的关闭顺序:
按创建对象的相反顺序关闭。】
过滤流:DataInputStream和ObjectInputStream
数据流:主要用于基本数据的读写:(写入的是二进制)
先写后读,并且读的时候应与写入时顺序一致。与平台无关,适合网络传输。
OutputStream os=new FileOutputStream("d:\\bb.txt");
DataOutputStream dos=new DataOutputStream(os);
dos.writeUTF("踩踩踩从");
dos.close();
os.close();
InputStream in=new FileInputStream("d:\\a.txt");
DataInputStream din=new DataInputStream(in);
对象流:写对象时,自定义的类要实现序列化。先写ObjectOutputStream,再写ObjectInputStream
Java序列化
是指把
Java对象转换为字节序列的过程
;而
Java反序列化
是指
把字节序列恢复为Java对象的过程
优点:一是,
实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),
二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。
implements
Serializable 才能保证独享可以以byte形式写进文件,接口里没定义任何常量和抽象
方法。
public
static
final
long
serialVersionUID=1111l;
private transient String pwd;
//保证敏感信息字段不被序列化,不会被读出
transient特点,
a.一旦变量被transient修饰,变量将不再成为对象持久化的部分,该变量内容在序列化后无法被访问。
b.transient只能修饰非静态成员变量,不能修饰类和方法。并且本地变量不能被transient修饰,如果变量是自定义变量需要实现Serializable接口。
c.被transient关键字修饰的变量不能再被序列化,静态变量不管是否被transient修饰,均不能被序列化。
OutputStream
os=new OutputStream();
ObjectOutputStream oos=new ObjectOutputStream(
os);
oos.writeObject(new User());
//输入流类似
输出流: //System.err-->PrintStream的对象;
PrintStream ps=new PrintStream(file); //System.out-->PrintStream的对象;标准输出流,输出到控制台
ps.
prinf("%d+%d=%d",5,2,8); //System.in-->InputStream的对象;标准输入流,键盘输入
PrintWriter pw=new PrintWriter(file); //字符输出流
pw.
prinf("%d+%d=%d",5,2,8);
Scanner scan=new Scanner(file);
PrintWriter pr=new PrintWriter("e:\\aa.txt","utf-8"); 最快速度写,aa.txt若不存在,会自动帮忙创建。
28.多线程:(eclipse启动后即为进程,main()执行时即为一个线程)
一个具体的线程也是由虚拟的 CPU 、代码和数据组成,其中代码与数据构成了线程体,线程的行为由它决定。
进程(资源分配):一种正在运行的程序,有自己的地址空间。 特点: 1.动态 2.并发 3.独立
线程(只能共享进程资源):进程内部的一个执行单元,程序中一个单一的程序控制流程。
多线程: 一个进程中同时运行多个线程,完成各自不同的工作
线程特点:
1.轻量级进程 2.独立调度的基本单元 3.可并发执行 4.共享进程资源。
线程创建的两种方式:
1.extends Thread 重写run()
/
/run()不能声明抛出任何异常,父类方法没有声明异常,不能大于父类异常范围。
//
不要重写start(),否则容易出现异常。
a.结构简单清晰,代码量少
b.无法继承其他的类,进行其他功能的扩展
2.class A implements Runnable 实现run() //内部使用
Thread.currentThread()
获取当前线程
Thread a=new Thread(new A()); //Thread 实现Runnable,可以作为A的构造参数。
a.可以继承别的类,但代码略复杂
b.线程资源共享,复用率高(推荐)
线程启动方式:
1.线程必须通过
start()方法启动(
就绪状态
)
2.
不能通过run()来启动线程,执行完毕前其他线程无法并行执行。
3.Java程序启动时,会马上创建主线程(
main在此线程上运行);当不再产生新线程时,程序即为单线程。
常用方法:
Thread.setName("sss");
Thread.currentThread().getName()
优先级:
setPriority(Thread.
MAX_PRIORITY
);
如果线程A创建了线程B,那么线程B将和线程A具有同样的优先级。
如果优先级为3的A线程中,创建了B线程,那么B的优先级也为3
。
移植到不同的操作系统中,最好只使用java提供的三个优先级,否则可能会报错。(java与不同系统的优先级映射不完全)
常用方法:
Join() 强行插入执行,插入的线程必须先执行完,才能执行被插入的线程和其他线程,按顺序执行。
如线程 A、B、C、D 在main()中执行,c.join()后main()线程会等待c线程执行结束之后才执行结束。
顺序 1.thread.start(); 2.thread.join(); 必须放在start()之后。
Sleep() 线程停止一段时间,转入阻塞状态,等到没有其他等待的线程,再执行(不会马上恢复执行)。
给其他线程执行的机会,不考虑其他线程的优先级,低优先级也可以执行。
yield() 将当前线程暂停,非阻塞线程,而是转入就绪状态。
等到没有其他等待的线程,
马上恢复执行
。
只给相同优先级或者更高优先级的线程一次运行的机会。
setDaemon() 指定线程设置成后台线程,
子线程随着主线程的结束而结束。必须在
线程启动之前把其设为后台线程
。
jvm的垃圾回收器其实就是一个后台线程; setDaemon函数必须在start函数之前设定,
否则会抛出IllegalThreadStateException异常;
顺序: 1. thread.setDaemon(true); 2.thread.start(); 必须在start之前。(在main()是这样)
stop() 结束线程,不推荐使用。
当一个线程执行System.out.println()或Syste.in.read()方法是,就会发出一个I/O请求,
该线程会放弃CPU,进入阻塞状态直到I/O结束才会恢复执行。
当线程退出run()时,就进入死亡状态,结束声明周期。
jvm采用抢占式调度模型:优先让可运行池中优先级高的线程占用cpu。
同步:
synchronized
(
this
){ //同步代码,同一时间只能由一个线程操作;推荐使用Runnable方式
ticket--;
System.out.println("票:"+ticket+"--"+Thread.currentThread().getName());
}
线程安全:
当多个线程访问同一个共享资源的时候,要保证某一个时刻只有一个线程控制和操作资源,使用同步代码锁和同步监视器来完成。
synchronized
(
this
){ //
this代表当前线程(同步监视器,临界资源)
ticket--;
System.out.println("票:"+ticket+"------------------"+Thread.currentThread().getName());
}
同步代码块两种方式:
synchronized
(Thread.currentThread())
或 synchronized(this) 或
synchronized(obj)
//obj须是一个共享对象,基本类型无效, 静态方法也可以加
synchronized,不会被继承
。
同步方法:
public
synchronized void sell
(){} //同步控制方法
正确?
用new关键字建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start进入就绪状态。
1.
当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。
另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
2.
当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程
仍然可以访问该object中的非synchronized(this)同步代码块。
3.
当
一个线程访问object的一个synchronized(this)同步代码块时
,
其他线程对
object中所有其它synchronized(this)同步代码块的访问将被阻塞
。
4.
当一个线程访问object的一个synchronized(this)同步代码块时,就
会获得这个object的对象锁
。其它线程对该object对象所有同步代码部分的访问都被暂时阻塞
5.两个不同的线程,在
加同步锁时应对同一种共享对象或者线程加锁。
同步锁不能用于实现不同线程之间的消息通讯。
线程通讯:
均是java.lang.Object类的方法,只能在同步方法或者同步代码块中使用,否则会抛出异常。
final void wait() 表示线程一直等待,直到其他线程通知;
会释放持有的锁资源
void wait(long timeout) 线程等待指定毫秒参数的时间
final void notify() 唤醒一个处于等待的线程(随机的唤醒)
final void notifyAll() 唤醒同一个对象上多有调用wait()方法的线程,优先级别高的线程优先运行
interrupt() 打断线程让出cpu
死锁,是指多个进程循环等待它方占有的资源而无限期地僵持下去的局面。
线程组:线程A创建线程B,默认跟A所属的线程组。一旦加入某个线程组,不能中途改变所属的线程组。
activeCount() 返回当前活着的线程。
enumerate(Thread []arr) 把当前活着的线程引用拷贝到arr中。
ThreadLocal:存放线程的局部变量,每个线程都有单独的局部变量,彼此不会共享。
解决多线程中数据因并发产生不一致问题。
耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
常用方法:
public T get(): 返回当前线程的局部变量 //ThreadLocal<T>
protected T initialValue():返回当前线程局部变量的初始值 //ThreadLocal类中有Map缓存,存储每个线程的局部变量。
public void set(T value): 设置局部变量值。
public static final ThreadLocal session = new ThreadLocal(); //创建线程局部变量session,用来保存Hibernate的Session
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
if (s == null) {
s = sessionFactory.openSession() ; // 如果Session还没有打开,则新开一个Session
session.set(s); //将新开的Session保存到线程局部变量中
}
return s;
}
Timer time=new Timer(true); //计时器,true代表成为后台线程
TimerTask task=new TimerTask() { //计时任务,实现了Runnable接口。
@Override
public void run() {
while(true){
a++;
}
}
};
time.schedule(task, 10, 500); //
time.schedule(task,
delay
,
period)
29.非阻塞与阻塞:
1.非阻塞:
把整个过程切换成小的任务,通过任务间协作完成。
事件驱动机制:事件到的时候触发,而不是同步的去监视事件。
线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的进程切换。
2.阻塞:若连接还没到来,那么 accept 会阻塞 , 程序运行到这里不得不挂起, CPU 转而执行其他线程。
异步结构图:
网络通讯协议:计算机网络中实现通讯需要的遵守的约定。
数据传输过程涉及的通讯协议:
集线器只涉及一层 //物理层
交换机涉及两层 //物理层+数据链路层
路由器涉及三层 //物理层+数据链路层+网络层
计算器涉及所有层次
应用层:Telenet:远程登录 FTP文件传输协议 SMTP:简单邮件传输协议 Http:超文本传输 DNS域名解析协议
Tcp:1.面向连接 2.点对点通讯 3.高可靠性 4.占用系统资源多、效率低
Udp: 1.无连接,传输不可靠,可能丢失
2.发送不管对方是否准备好,接收方收到也不确认
3.可以广播发送,非常简单的协议,开销小。
IP: 127.0.0.1 本机地址(localhost),路由器修改密码是要用
192.168.0.0--192.168.255.255 私有地址,非注册地址,给阻止结构内部使用。
>>> 无符号右移 >>右移
常用方法:
InetAddress.getLocalHost(); //获取主机名,如kkk InetAddress不能实例化
addr=InetAddress.getByName("61.135.253.15");
addr.getHostAddress() //返回163服务器的ip: 61.135.253.15
addr.getHostName(); //输出ip而不是域名。如果这个ip地址不存在或者DNS服务器不允许进行ip地址和域名的映射,
//getHostName方法直接返回这个ip地址。
InetSocketAddress可以实例化,带端口
Socket通讯:Socket实际是网络传输层供给应用层的编程接口。
客户端程序创建一个套接字,并尝试连接服务器的套接字。当连接建立时,服务器会创建一个Socket对象。
客户端和服务器现在可以通过对Socket对象的写入和读取来进行进行通信。
两台计算机之间使用套接字建立TCP连接时会出现:连接成功后使用I/O进行通讯。
- 服务器实例化一个ServerSocket对象,表示通过服务器上的端口通信。
- 服务器调用 ServerSocket类 的accept()方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
- 服务器正在等待时,一个客户端实例化一个Socket对象,指定服务器名称和端口号来请求连接。
- Socket类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个Socket对象能够与服务器进行通信。
- 在服务器端,accept()方法返回服务器上一个新的socket引用,该socket连接到客户端的socket。
在请求和应答的通讯过程中,不能马上关闭I/O流,否则会报异常,应放到最后才关闭。
I/O和JDBC等的连接,需要自己手动关闭,JVM不负责关闭。
next()只接受空格之前的数据 nextLine()接收回车之前的数据
UDP:(I/O流的操作不是必须的)
DatagramSocket ds = new DatagramSocket(); //建立客户端连接,使用系统分配的一个本机未用端口。一般客户端的连接没必要指定端口。
流程:1、在发送数据时,将需要发送的数据内容先转换为byte数组,再将数据内容、服务器IP和服务器端口号一起
构造成一个DatagramPacket类型的对象,发送时直接发送该对象即可。
进行数据传输时,系统只是尽全力
传输数据,但是并不保证数据一定被正确传输,如果数据在传输过程中丢失,那就丢失了。
2、接收数据在Java语言中的实现是这样的:首先构造一个数据缓冲数组,该数组用于存储接收的服务器端反馈
数据,该数组的长度必须大于或等于服务器端反馈的实际有效数据的长度。然后以该缓冲数组为基础构造一
个DatagramPacket数据包对象,最后调用连接对象的receive方法接收数据即可。接收到的服务器端反馈数
据存储在DatagramPacket类型的对象内部。
UDP数据包: 需先启动server端等待接收,再启动客户端发送数据。
res=scan.nextLine(); //直接使用res.getLength()造成数据丢失。
byte arr[]=res.getBytes();
dp2 = new DatagramPacket(res.getBytes(),
arr.
length
, dp.getAddress(), dp.getPort());
//arr.
length 在此处只能只用数组的长度,否则会出现少字符。
ds.send(dp2);
DatagramSocket:发送或接受数据包 //没有指定端口时,系统会随机分配一个端口。
client: DatagramSocket ds=new DatagramSocket(9999) //9999为client自己发送和接收数据的端口
server
: DatagramSocket ds=new DatagramSocket(9999
) //9999为服务器自己发送和接收数据的端口
两台机器通讯才能写同样的端口;如果是电脑上调试,不能写同一个端口,否则会报错。
new DatagramPacket(buf, length, address, port) //port为指定服务器的接收端口
DatagramPacket:数据包
DatagramPacket receiveDp = new DatagramPacket(b,b.length); //接收的数据包,存放在b数组中
receiveDp.getData(); //获得缓冲数组
receiveDp.getLength(); //获得有效数据长度
URL:统一资源定位符,格式:协议、存放资源的主机域名、端口号和资源文件名
UDP传输对象:
User user=
new
User
(
"kkk"
,
"aaa"
);
bao=new
ByteArrayOutputStream(); //
ByteArrayOutputStream() 使用字节数组流来转化对象
obj=new ObjectOutputStream(bao); //将对象写入对象流,然后再通过字节数组流获取user的字节数组。
obj.writeObject(user);
byte[] arr=bao.toByteArray();
dp=new DatagramPacket(arr, arr.length,
InetAddress.
getByName
(
"localhost"
), 8888);
类的静态加载:编译时查找需要的类,都会要求已存在,没有则编译不通过。
类的动态加载:把编译时的检查异常移到运行时去检查,只对需要的逻辑进行检查,其他地方不检查。
Class<?> c=Class.forName("com.kkk.Apple"); //未知类型,用?
cmd下动态执行加载类命令,java -d . test.java
int arr[]={1,2};
int brr[]={2,2};
int crr[][]={{1},{2,3,4}};
Class<?> c1=arr.getClass();
Class<?> c2=brr.getClass();
Class<?> c3=crr.getClass();
System.out.println(c1==c2); //都是一维数组 true
System.out.println(c2==c3); //一维和二维不一样,false
反射技术:(反编译)
在运行状态中,对于任意一个类,都能够知道这
个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;
这种动态获取的以及动态调用对象的方法的功能成为反射机制。
在编译时不确定哪个类被加载,而在程序运行时才进行加载、探知、使用。
- idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
功能体现:
在运行时判定任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判定任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;生成动态代理。
//第一种方式:
Class c1 = Class.forName("com.Student"); //包名+类名,获得模板类的对象
c1.getName(); //获取全路径名
c1.getSimpleName() //获取类名
Modifier.toString(c1.getModifier()) //获取权限修饰符
Class c2 = Employee.class;
//java语言中任何一个java对象都有getClass 方法
Employee e = new Employee();
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
反射的主要类:
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
Ø Class类:代表一个类
Ø Field 类:代表类的成员变量(属性)
getField() 获取共同属性
Ø Method类:代表类的成员方法
getMethod()返回本类、父类和父接口声明的public方法
Method m6=getMethod("getName",null) //对void可以这样用
m6.invoke(stu,20) //设置年龄
Ø Constructor 类:代表类的构造方法 //最好提供一个空参的构造,在框架学习中可以发现很多都是靠反射无参构造生成
getConstructors() 只获取public构造函数
getDeclaredConstructors 获取声明的构造函数
Student stu=(Student)getConstructor(String.class).newInstance("aa") 获取public有参构造
Ø Array类:提供了动态创建数组,以及访问数组的元素的静态方法
List<String> mlist=new ArrayList<String>();
mlist.add("aaa");
Class cc2=mlist.getClass();
Method mt=cc2.getMethod("add", Object.class)
;
//不能使用add()
mt.invoke(mlist, 123);//可以插入123
//利用反射可以绕过泛型对于源文件数据类型的检查,换句话说,泛型只是在编译期间起作用,之后泛型意义不大
利用反射实现工厂方法:
Class
c=Class.forName(str);
//Factory加载
reflect.reflcet02.Apple
return (Fruit)c.newInstance();
Factory.
getFruit
(
"reflect.reflcet02.Apple"
).show(); //Test
或者用Properties来动态读取配置文件
File f=new File("fruit.properties"); //将属性文件存在properties中
Properties pro=
new
Properties();
if
(f.exists()){
pro.load(new FileInputStream(f));
}
//读取属性
Factory.getFruit(Factory.getPro().getProperty("Apple")).show(); //测试