java框架总结

时间:2024.4.21

Java基础

java语言的跨平台性

    java的跨平台特性也被称为可移植性、与平台无关性、或者一次编写处处运行他的意思就是如果用java语言编写一个应用,那么就可以在不同发热平台上运行,而不需要为不同的平台单独运行开发。之所以能实现跨平台的特性,主要得益于java的虚拟机(JVM),JVM解释器在运行java应用时根据当前平台进行解释,解释成符合当前平台规范的机器码,所以可以实现同样的应用在不太能够的平台上都能运行

java语言的特点

java语言的特点:1、跨平台性:一个应用可以不经过修改直接运行到不停的平台上去;2、面向对象:java语言是一门面向对象语言可以直接使用对象属性和行为,可以使用面向对象的四项进行分析设计,并实现整个应用。3、解释执行java应用时,JVM中的解释器将解释类文件,生成符合当前平台的字节码。4、自动回收:java应用中的垃圾回收是自定进行的,JVM中的后台线程将监视内存中数据的使用,当内存中的数据不再呗引用时,将作为垃圾回收,而不需要程序员手动回收

java类中包含的元素级作用

    JAVA类中主要包含属性、方法、构造方法、块以及内部类。属性用来定义对象的数据;方法用来定义对象的行为;构造方法可以用来创建对象;块能够用来在类加载时执行操作或者在每次实例化前执行通用操作;内部类作为类的一个成员存在,能够访问外部类的属性和方法。构造方法的作用和特征构造方法的作用是用来创建对象,使用关键字new调用。构造方法的名字必须与类的名字相同,并且大小写敏感,同时构造方法不能声明返回值类型,可以使用用任意一中访问修饰符,但是不能使用其他修饰符就行修饰,如static、final、abstract等修饰符都可以修饰构造方法

方法的重载方法重载指的是在一个类中可以声明多个相同名字的方法,而方法的形式参数有区别。调用这些同名的方法时,JVM会根据实际参数的不同绑定到不同的方法。

java语言中的权限访问修饰符和每种权限的含义

    Java语言中有四种权限访问修饰符,即public、protected、同包以及private,public表示公共权限,即任何包中都可以访问:protected表示受保护权限,即同包中可以访问,同包中的子类可以访问:同包权限是默认权限,即不显示指明权限修饰符的时候就是同包权限,表示只有同包中可以访问:private是私有权限,表示只能在本类中访问。

java语言中的八种基本数据类型和每种数据类型的含义及长度Java语言的八种基本数据类型有:byte字节型,8位长度:short短整型,16位长度,int整型,32位长度:long长整型,64位长度:float单精度浮点型。32位长度:double双精度浮点型,64位长度:char字符型,16位长度:boolean型,表示逻辑值,有true和false两个值,分别表示真和假

引用类型,引用类型和基本数据类型的区别

    Java语言中除了基本数据类型之外的类型,都称为引用类型。引用类型就是类的类型,所有的对象都是引用类型,包括数组对象。引用类型必须使用new调用构造方法进行赋值,引用类型的变量拥有自己的属性和方法,可以使用圆点调用自己的属性和方法。基本数据类型直接使用=号进行赋值,且没有自己的属性和方法,往往都在声明属性或方法时使用。对于String对象,可以使用“=”赋值也可以使用new关键字赋值,他们的区别使用“=”赋值不一定每次都创建一个新的字符串,而是从“字符串实例池”中查找字符串。使用new进行赋值,则每次都创建一个新的字符串。String类是一个”不可变类“,”不可变类“的含义String类是一个不可变类,即immutable类。所谓不可变,意思是当一个字符串被初始化后,它的值就不会被改变。例如,String s=new String(“hello”)为将初始化一个值为hello的字符串,如果调用 s.toUpperCase()看起来是把hello变为大写的HELLO,然而事实上并不会把已有的hello变为HELLO,而是在新的空间初始化一个HELLO字符串。也正因为有这种不可变性,所以才能支持“字符串实例池”的使用。

    参考答案:所谓的不可变类,就是当字符串初始化后,就不能够被改变。

String类和stringBuffer类的区别

    String类是不可变类,字符串一旦初始化后,就不能在被改变。而Stringbuffer类是可变类,字符串值可以被改变。常常在实际应用中看到类似这样的代码:String s = new(”hello“);s+=”world“这两句代码首先创建一个字符hello,然后将world追加到hello的结尾并重新赋值给变量s。然后。这个过程实际上是这样的:首先创建一个stringBuffer对象,然后用Stringbuffer类的append方法追加字符串,左后对stringBuffer调用toSting方法合成字符串返回,使用+号连接字符串时,本质上是使用了可变的StringBuffer类,经变动肯定性能效率受到影响,所以建议需要追加字符串时,可以考虑直接使用StringBuffer类。参考答案:String类是不可变类,即字符串值一旦初始化后就不可能改变。StringBuffer是可变字符串类,类似String的缓冲区,可以修改字符串的值。

stringBuffer和StringBuilder类有什么区别

    StringBuffer是JDK5中的增加的一个类,在以前版本中不存在这个类。StringBuilder中的方法和stringBuffer中的方法基本相同,但是stringBuffer是线程安全的,而StringBuilder不是线程安全的因此在不考虑同步的情况下,StringBuilder又更好的性能

包装器的类型和作用包装类器包括Byte、Short、Integer、Long、Float、Double、Character、Boolean等类,主要用来对byte、short、integer、long、float、double、character、boolean这八种基本数据类型进行包装,使其称为引用类型。

使用static修饰符属性或方法后,属性和方法有什么特征

    static修饰属性或方法后,属性饿汉方法不再属于某个特定的对象,而是所有共享,也可以说是static成员不依赖某个对象,在类加载是就被初始化。static修饰符的属性或非,可以直接使用类名调用,而不用先实例化对象在调用。

使用final修饰属性后的特征属性可以是变量也可以是常量,如果是常量,就需要使用这个final修饰。如果使用final修饰了某个属性,那么该属性值一旦被赋值,就不能修改,实际中常常有这样的代码private static final int ERROR=0;也就是说,常常会生命静态的常量。静态常量的命名规范非常特殊,往往都是用大写字,如果包含多个单词,每个单词之间使用下划线连接。静态常量的意思是,该类所有的对象都拥有一个不变的常量ERROR,作为0.API中很多类都定义了很多的静态常量,使用时直接使用类名调用即可。

    参考答案:fianl修饰属性后,属性就成为一个常量。常量只要被赋值,就不能被改变。

操作符==的作用实际编程中,==是非常常用的操作符。很多初级程序员会使用这样的代码if(s==”save”0{},结果会发现,即使当字符串s的值为save时,if条件依然不能被执行。是==在比较引用类型时,比较的是两个对象的虚地址,而不是内容。要比较两个对象的内容是否相同,往往需要使用equal方法,例如if(s.equals(“save”)){}。==比较基本类型时,将比值的二进制是否相等,例如(x==0.5){}。值得注意的是,与空指针null值进行比较,往往用==进行,例如if(s==null||s.equals(“”)),表示如果字符串是空指针或者空串。

    参考答案:==可以用来比较基本类型或者引用类型。比较基本类型时,==用来比较二进制的值,比较引用类型时,用来比较对象的虚地址。

&&和&的区别和练习

    实际编程中,常常需要使用“与”或者“或”的逻辑。其中&&和&存在一定区别&&可能发生各路问题,例如if(s!=null&&s.length()==6)中,如果要的值为null,那么第一表达式的值为false,返回值肯定是false,不会计算第二个表达式的值,这就是短路。然而使用&,例如if(s!=null&s.length()==6),假设s的值为,null,返回值肯定是false,但是会判断第二个表达式的值,将发生空指针异常。实际工作中,经常使用&&操作符。

    参考答案:&&会发生短路问题,当第一个表达式的值为false时,将直接返回结果为false而不会判断第二个表达式的值。而&不会发生短路问题,即使第一个表达式的值是false,会判断第二个表达式的值。

for循环语句中的break语句和continue语句的使用

    很多时候,循环是为了查找某些符合条件的数据,只要找到就没有必要继续下去,称为中断循环,break语句就可以用来中断循环。而continue语句恰恰相反,是用来继续下一次循环。值得注意的是,java语言中可以再循环前面加标号,即label,然后可以使用break或continue中断或继续标号的循环。

    参考答案:break可以用来中断循环,continue可以用来继续下一次循环。

对象:

匿名对象使用的场景:

    1.当对方法只进行一次调用的时候,可以使用匿名对象

    2.当对象对成员进行多次调用的时,不能使用匿名对象.必须给对象棋名字

成员变量和局部变量的区别:

1:成员变量直接定义在类中。

   局部变量定义在方法中,参数上,语句中。

2:成员变量在这个类中有效。

局部变量只在自己所属的大括号内有效,大括号结束,局部变量失去作用域。

3:成员变量存在于堆内存中,随着对象的产生而存在,消失而消失。

局部变量存在于栈内存中,随着所属区域的运行而存在,结束而释放。

构造函数:用于给对象进行初始化,是给与之对应的对象进行初始化,它具有针对性,函数中的一种

特点:

    1.该函数的名称和所在类的名称相同.

    2.不需要定义返回值类型

    3.该函数没有具体的返回值

记住:所有对象创建时,都需要初始化可以使用

构造函数和一般函数有什么区别呢?

1:两个函数定义格式不同。

2:构造函数是在对象创建时,就被调用,用于初始化,而且初始化动作只执行一次。

    一般函数,是对象创建后,需要调用才执行,可以被调用多次。

什么时候使用构造函数呢?

分析事物时,发现具体事物一出现,就具备了一些特征,那就将这些特征定义到构造函数内。

构造代码块和构造函数有什么区别?

构造代码块:是给所有的对象进行初始化,也就是说,所有的对象都会调用一个代码块。只要对象一建立。就会调用这个代码块。

构造函数:是给与之对应的对象进行初始化。它具有针对性。

static:★★★ 关键字,是一个修饰符,用于修饰成员(成员变量和成员函数)。

特点:

1,想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。

2,被静态修饰的成员,可以直接被类名所调用。也就是说,静态的成员多了一种调用方式。类名.静态方式。

3,静态随着类的加载而加载。而且优先于对象存在。

弊端:

1,有些数据是对象特有的数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据。这样对事物的描述就出了问题。所以,在定义静态时,必须要明确,这个数据是否是被对象所共享的。

2,静态方法只能访问静态成员,不可以访问非静态成员。

因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员。

3,静态方法中不能使用this,super关键字。

因为this代表对象,而静态在时,有可能没有对象,所以this无法使用。

4,主函数是静态的。

静态的注意:静态的生命周期很长

静态代码块:就是一个有静态关键字标示的一个代码块区域.定义在类中

作用:

    可以完成类的初始化,静态代码块随着类的加载而执行,而且只执行一次(new 多个对象就只执行一次).如果和主函数在同一个类中,优先于主函数执行.

静态代码块、构造代码块、构造函数同时存在时的执行顺序:静态代码块 à构造代码块 à构造函数;

设计模式:

解决问题最行之有效的思想。是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

Java中的单例模式

解决的问题:保证一个类在内存中的对象唯一性

比如:多程序读取一个配置文件时,建议配置文件封装成对象,会方便操作其中的数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存是唯一的

Runtime()方法就是单例设计模式进行设计的

如何保证对象的唯一性呢?

思想:

    1.不让其他程序创建该类对象,

    2.在本类中创建一个本类对象

    3.对外提供方法,让其他程序获取这个对象。

步骤:

    1.因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法在创建该类对象;

    2.就在类中创建一个本类的对象

    3.定义一个方法,返回该对象,让其他程序可以以通过方法就得到本类对象;

代码体现:

    1.私有化构造函数;

    2.创建私有并静态化的本类对象;

    3.定义公有并静态的方法,返该对象。

饿汉式

Class Single{

    private Single(){}//私有化构造函数。

    private static Single s = new Single();//创建私有并静态的本类对象。

    public static Single getInstance(){//定义公有并静态的方法,返回该对象。

       return s

    }

}

懒汉式:延迟加载方式

Class  Single2{

    private single2(){}

    private static Single2 s = null;

    public static Single2 getInstance(){

       if(s==null)

           s = new Single2();

       return s;

}

}

继承:

好处:

    1.提高了代码的复用性。

    2.让类与类之间产生了关系,提供了另外一个特征多态的前提。

父类的由来:其实是由多个类不断向上抽取共性内容而来的。

java中对于继承,java只支持单继承。java虽然不直接支持多继承,但是保留了这种多继承机制,进行改良。

单继承:一个类只能有一个父类。

多继承:一个类可以有多个父类。

为什么不支持多继承呢?

因为当一个类同时继承两个父类时,两个父类中有相同的功能,那么子类对象调用该功能时,运行哪一个呢?因为父类中的方法中存在方法体。

但是java支持多重继承。A继承B  B继承C  C继承D。

多重继承的出现,就有了继承体系。体系中的顶层父类是通过不断向上抽取而来的。它里面定义的该体系最基本最共性内容的功能。

所以,一个体系要想被使用,直接查阅该系统中的父类的功能即可知道该体系的基本用法。那么想要使用一个体系时,需要建立对象。建议建立最子类对象,因为最子类不仅可以使用父类中的功能。还可以使用子类特有的一些功能。

简单说:对于一个继承体系的使用,查阅顶层父类中的内容,创建最底层子类的对象。子父类出现后,类中的成员都有那些特点:

    1.成员变量。

      当子父类中出现一样的属性时,子类类型的对象,调用该属性,值是子类的属性。

      如果想调用父类中的属性时,需要一个关键字super

      This:代表的是本类类型的对象引用。

      super:代表是子类所属的父类中的内存空间引用。

      注意:子父类中通常是不会出现同名成员变量的,因为父类中只要定义了,子类就不用在定义了,直接继承过来就可以使用了。

    2.成员函数

    当子父类中出现了一模一样的方法时,建立子类对象会运行子类中的方法。好像父类中的方法被覆盖掉一样。所以这种情况。是函数的另一个特性:覆盖(复写,重写)

    什么时候使用覆盖呢?当一个类的功能内容需要修改时,可以通过覆盖来实现。

    3.构造函数

    发现子类构造函数运行时,先运行了父类的构造函数。为什么呢?

    原因:子类的所有构造函数中的第一行,其实都有一条隐身的语句super();

super(): 表示父类的构造函数,并会调用于参数相对应的父类中的构造函数。而super():是在调用父类中空参数的构造函数。

为什么子类对象初始化时,都需要调用父类中的函数?(为什么要在子类构造函数的第一行加入这个super()?)

因为子类继承父类,会继承到父类中的数据,所以必须要看父类是如何对自己的数据进行初始化的。所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程。

注意:子类中所有的构造函数都会默认访问父类中的空参数的构造函数,因为每一个子类构造内第一行都有默认的语句super();

如果父类中没有空参数的构造函数,那么子类的构造函数内,必须通过super语句指定要访问的父类中的构造函数。

如果子类构造函数中用this来指定调用子类自己的构造函数,那么被调用的构造函数也一样会访问父类中的构造函数。

问题:super()和this()是否可以同时出现的构造函数中。

两个语句只能有一个定义在第一行,所以只能出现其中一个。

super()或者this():为什么一定要定义在第一行?

因为super()或者this()都是调用构造函数,构造函数用于初始化,所以初始化的动作要先完成。

final特点:

1:这个关键字是一个修饰符,可以修饰类,方法,变量。

2:被final修饰的类是一个最终类,不可以被继承。

3:被final修饰的方法是一个最终方法,不可以被覆盖。

4:被final修饰的变量是一个常量,只能赋值一次。

抽象类的特点:

1:抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰(可以描述类和方法,不可以描述变量)。

2:抽象方法只定义方法声明,并不定义方法实现。

3:抽象类不可以被创建对象(实例化)。

4:只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

模板方法设计模式:

解决的问题:当功能内部一部分实现时确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

abstract class GetTime{

    public final void getTime(){ //此功能如果不需要复写,可加final限定

       long start = System.currentTimeMillis();

       code(); //不确定的功能部分,提取出来,通过抽象方法实现

       long end = System.currentTimeMillis();

       System.out.println("毫秒是:"+(end-start));

    }

    public abstract void code(); //抽象不确定的功能,让子类复写实现

}

class SubDemo extends GetTime{

    public void code(){ //子类复写功能方法

       for(int y=0; y<1000; y++){

           System.out.println("y");

       }

    }

}

匿名内部类:

//面试

                   //1

       new Object(){

           void show(){

              System.out.println("show run");          

           }

       }.show();

                   //2

       Object obj = new Object(){

           void show(){

              System.out.println("show run");

           }

       };

       obj.show();

      

       1和2的写法正确吗?有区别吗?说出原因。

       写法是正确,1和2都是在通过匿名内部类建立一个Object类的子类对象。

       区别:

       第一个可是编译通过,并运行。

第二个编译失败,因为匿名内部类是一个子类对象,当用Object的obj引用指向时,就被提升为了Object类型,而编译时检查Object类中是否有show方法,所以编译失败。

class InnerClassDemo6 {

    +(static)class Inner{

       void show(){}

    }

    public void method(){

       this.new Inner().show();//可以

    }

    public static void main(String[] args) {//static不允许this

                   This.new Inner().show();//错误,Inner类需要定义成static

    }

}

interface Inter{

    void show();

}

class Outer{//通过匿名内部类补足Outer类中的代码。

    public static Inter method(){

       return new Inter(){

           public void show(){}

       };

    }

}

class InnerClassDemo7 {

    public static void main(String[] args) {

                   Outer.method().show();

    /*

       Outer.method():意思是:Outer中有一个名称为method的方法,而且这个方法是静态的。

       Outer.method().show():当Outer类调用静态的method方法运算结束后的结果又调用了show方法,意味着:method()方法运算完一个是对象,而且这个对象是Inter类型的。

    */

       function (new Inter(){

           public void show(){}

       }); //匿名内部类作为方法的参数进行传递。

    }

    public static void function(Inter in){

       in.show();

    }

}

异常:

异常处理原则:功能抛出几个异常,功能调用如果进行try处理,需要与之对应的catch处理代码块,这样的处理有针对性,抛几个就处理几个。

特殊情况:try对应多个catch时,如果有父类的catch语句块,一定要放在下面。

throw 和 throws关键字的区别:

    throw用于抛出异常对象,后面跟的是异常对象;throw用在函数内.

    throws用于抛出异常类,后面跟的异常类名,可以跟多个.用逗号隔开.throws用在函数上.

异常分为两种:

    1.编译时被检查的异常,只要Exception及其子类都是编译时被检测的异常.

    2.运行时异常,其中Exception有一个特殊的子类RuntimeException,以及RuntimeException的子类是运行异常,也就是说这个异常时编译时不被检查的异常.

编译时被检查的异常和运行时异常的区别:

编译被检查的异常在函数内被抛出,函数必须要声明,否编译失败。

声明的原因:是需要调用者对该异常进行处理。

运行时异常如果在函数内被抛出,在函数上不需要声明。

不声明的原因:不需要调用者处理,运行时异常发生,已经无法再让程序继续运行,所以,不让调用处理的,直接让程序停止,由调用者对代码进行修正。

定义异常处理时,什么时候定义try,什么时候定义throws呢?

功能内部如果出现异常,如果内部可以处理,就用try;

如果功能内部处理不了,就必须声明出来,让调用者处理。

多线程:★★★★

进程:正在进行中的程序。其实进程就是一个应用程序运行时的内存分配空间。

线程:其实就是进程中一个程序执行控制单元,一条执行路径。进程负责的是应用程序的空间的标示。线程负责的是应用程序的执行顺序。

线程和进程的主要差别体现在以下两个方面:

1)、同样作为基本的执行单元,线程是划分得比进程更小的执行单位。

2)、每个进程都有一段专用的内存区域。与此相反,线程却共享内存单元(包括代码和数据),通过共享的内存单元来实现数据交换、实时通信与必要的同步操作。

随机性的原理:因为cpu的快速切换造成,哪个线程获取到了cpu的执行权,哪个线程就执行。

创建线程的第一种方式:继承Thread,有子类复写run方法.

步骤:

    1.定义继承Thread类;

    2.目的是复写run方法,将要让线程运行的代码都存储到run方法;

    3.通过创建Thread类的子类对象,创建线程对象;

    4.调用线程的start方法,开启线程,并运行run方法.

线程状态:

    被创建:start()

    运行:具备执行资格,同时具备执行权;

    冻结:sleep(time),wait()—notify()唤醒;线程释放了执行权,同时释放执行资格;

    临时阻塞状态:线程具备cpu的执行资格,没有cpu的执行权;

    消亡:stop()

创建线程的第二种方式:实现一个接口Runnable:

步骤:

    1.定义类实现Runnable接口.

    2.覆盖接口中的run方法(用于封装线程要运行的代码)

    3.通过Thread类创建线程对象;

    4.将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数.

      为什么说要传递呢?因为让线程对象明确要运行的run方法所属的对象.

    5.调用Thread对象的start方法.开启线程,并运行Runnable接口子类中的run方法.

//面试

       new Thread(new Runnable(){  //匿名

           public void run(){

              System.out.println("runnable run");   

           }

       })

       {

           public void run(){

              System.out.println("subthread run");

           }

       }.start();  //结果:subthread run

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

Try {

Thread.sleep(10);

}catch(InterruptedException e){}// 当刻意让线程稍微停一下,模拟cpu  切换情况。

多线程安全问题的原因

通过图解:发现一个线程在执行多条语句时,并运算同一个数据时,在执行过程中,其他线程参与进来,并操作了这个数据。导致到了错误数据的产生。

涉及到两个因素:

1,多个线程在操作共享数据。

2,有多条语句对共享数据进行运算。

原因:这多条语句,在某一个时刻被一个线程执行时,还没有执行完,就被其他线程执行了。

解决安全问题的原理:

只要将操作共享数据的语句在某一时段让一个线程执行完,在执行过程中,其他线程不能进来执行就可以解决这个问题。

如何进行多句操作共享数据代码的封装呢?

java中提供了一个解决方式:就是同步代码块。

格式:

synchronized(对象) {  // 任意对象都可以。这个对象就是锁。

    需要被同步的代码;

}

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

同步:★★★★★

好处:解决了线程安全问题。

弊端:相对降低性能,因为判断锁需要消耗资源,产生了死锁。

★考点问题:请写一个延迟加载的单例模式?写懒汉式;当出现多线程访问时怎么解决?加同步,解决安全问题;效率高吗?不高;怎样解决?通过双重判断的形式解决。

//懒汉式:延迟加载方式。

当多线程访问懒汉式时,因为懒汉式的方法内对共性数据进行多条语句的操作。所以容易出现线程安全问题。为了解决,加入同步机制,解决安全问题。但是却带来了效率降低。

为了效率问题,通过双重判断的形式解决。

class Single{

    private static Single s = null;

    private Single(){}

    public static Single getInstance(){ //锁是谁?字节码文件对象;

       if(s == null){

           synchronized(Single.class){

              if(s == null)

                  s = new Single();

           }

       }

       return s;

    }

}

等待唤醒机制:涉及的方法:

    wait:将同步中的线程处于冻结状态。释放了执行权,释放了资格。同时将线程对象存储到线程中

    notify:唤醒线程池中的某一个等待线程

    notifyAll:唤醒的是线程池中的所有线程

注意:

1:这些方法都需要定义在同步中。

2:因为这些方法必须要标示所属的锁。

    你要知道 A锁上的线程被wait了,那这个线程就相当于处于A锁的线程池中,只能A锁的notify唤醒。

3:这三个方法都定义在Object类中。为什么操作线程的方法定义在Object类中?

    因为这三个方法都需要定义同步内,并标示所属的同步锁,既然被锁调用,而锁又可以是任意对象,那么能被任意对象调用的方法一定定义在Object类中。

wait和sleep区别:分析这两个方法:从执行权和锁上来分析:

wait:可以指定时间也可以不指定时间。不指定时间,只能由对应的notify或者notifyAll来唤醒。

sleep:必须指定时间,时间到自动从冻结状态转成运行状态(临时阻塞状态)。

wait:线程会释放执行权,而且线程会释放锁。

Sleep:线程会释放执行权,但不是不释放锁。

线程的停止:通过stop方法就可以停止线程。但是这个方式过时了。

停止线程:原理就是:让线程运行的代码结束,也就是结束run方法。

怎么结束run方法?一般run方法里肯定定义循环。所以只要结束循环即可。

第一种方式:定义循环的结束标记。

第二种方式:如果线程处于了冻结状态,是不可能读到标记的,这时就需要通过Thread类中的interrupt方法,将其冻结状态强制清除。让线程恢复具备执行资格的状态,让线程可以读到标记,并结束。

--< java.lang >-- String字符串:★★★☆

特点:字符串一旦被初始化,就不可以被改变,存放在方法区中的常量池中。

1:构造方法:将字节数组或者字符数组转成字符串。

String s1 = new String();//创建了一个空内容的字符串。

String s2 = null;//s2没有任何对象指向,是一个null常量值。

String s3 = "";//s3指向一个具体的字符串对象,只不过这个字符串中没有内容。

//一般在定义字符串时,不用new。

String s4 = new String("abc");

String s5 = "abc"; 一般用此写法

new String(char[]);//将字符数组转成字符串。

new String(char[],offset,count);//将字符数组中的一部分转成字符串。

2:一般方法:

    按照面向对象的思想:

2.1 获取:

    2.1.1:获取字符串的长度。length();

    2.1.2:指定位置的字符。char charAt(int index);

    2.1.3:获取指定字符的位置。如果不存在返回-1,所以可以通过返回值-1来判断某一个字符不存在的情况。

           int indexOf(int ch);//返回第一次找到的字符角标

           int indexOf(int ch,int fromIndex); //返回从指定位置开始第一次找到的角标

           int indexOf(String str); //返回第一次找到的字符串角标

           int indexOf(String str,int fromIndex);

           int lastIndexOf(int ch);

           int lastIndexOf(int ch,int fromIndex);

           int lastIndexOf(String str);

           int lastIndexOf(String str,int fromIndex);

    2.1.4:获取子串。

           String substring(int start);//从start位开始,到length()-1为止.

           String substring(int start,int end);//从start开始到end为止。//包含start位,不包含end位。

           substring(0,str.length());//获取整串

2.2 判断:

    2.2.1:字符串中包含指定的字符串吗?

           boolean contains(String substring);

    2.2.2:字符串是否以指定字符串开头啊?

           boolean startsWith(string);

    2.2.3:字符串是否以指定字符串结尾啊?

           boolean endsWith(string);

    2.2.4:判断字符串是否相同

           boolean equals(string);//覆盖了Object中的方法,判断字符串内容是否相同。

    2.2.5:判断字符串内容是否相同,忽略大小写。

           boolean equalsIgnoreCase(string) ;

2.3 转换:

    2.3.1:通过构造函数可以将字符数组或者字节数组转成字符串。

    2.3.2:可以通过字符串中的静态方法,将字符数组转成字符串。

           static String copyValueOf(char[] );

           static String copyValueOf(char[],int offset,int count);

           static String valueOf(char[]);

           static String valueOf(char[],int offset,int count);

    2.3.3:将基本数据类型或者对象转成字符串。

           static String valueOf(char);

           static String valueOf(boolean);

           static String valueOf(double);

           static String valueOf(float);

           static String valueOf(int);

           static String valueOf(long);

           static String valueOf(Object);

    2.3.4:将字符串转成大小写。

           String toLowerCase();

           String toUpperCase();

    2.3.5:将字符串转成数组。

           char[] toCharArray();//转成字符数组。

           byte[] getBytes();//可以加入编码表。转成字节数组。

    2.3.6:将字符串转成字符串数组。切割方法。

           String[] split(分割的规则-字符串);

    2.3.7:将字符串进行内容替换。注意:修改后变成新字符串,并不是将原字符串直接修改。

           String replace(oldChar,newChar);

           String replace(oldstring,newstring);

    2.3.8: String concat(string); //对字符串进行追加。

           String trim();//去除字符串两端的空格

     int compareTo();//如果参数字符串等于此字符串,则返回值 0;如果此字符串按字典顺序小于字符串参数,则返回一个小于 0 的值;如果此字符串按字典顺序大于字符串参数,则返回一个大于 0 的值。

--< java.lang >-- StringBuffer字符串缓冲区:★★★☆

构造一个其中不带字符的字符串缓冲区,初始容量为 16 个字符。

特点:

1:可以对字符串内容进行修改。

2:是一个容器。

3:是可变长度的。

4:缓冲区中可以存储任意类型的数据。

5:最终需要变成字符串。

容器通常具备一些固定的方法:

1,添加。

    StringBuffer append(data):在缓冲区中追加数据。追加到尾部。

    StringBuffer insert(index,data):在指定位置插入数据。

2,删除。

    StringBuffer delete(start,end);删除从start至end-1范围的元素

    StringBuffer deleteCharAt(index);删除指定位置的元素

//sb.delete(0,sb.length());//清空缓冲区。

3,修改。

    StringBuffer replace(start,end,string);将start至end-1替换成string

    void setCharAt(index,char);替换指定位置的字符

    void setLength(len);将原字符串置为指定长度的字符串

4,查找。(查不到返回-1)

    int indexOf(string);返回指定子字符串在此字符串中第一次出现处的索引。

    int indexOf(string,int fromIndex);从指定位置开始查找字符串

    int lastIndexOf(string);返回指定子字符串在此字符串中最右边出现处的索引。

    int lastIndexOf(string,int fromIndex);从指定的索引开始反向搜索

5,获取子串。

    string substring(start);返回start到结尾的子串

    string substring(start,end); 返回start至end-1的子串

6,反转。

    StringBuffer reverse();字符串反转

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

--< java.lang >-- StringBuilder字符串缓冲区:★★★☆

JDK1.5出现StringBuiler;构造一个其中不带字符的字符串生成器,初始容量为 16 个字符。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。

方法和StringBuffer一样;

StringBuffer 和 StringBuilder 的区别:

StringBuffer线程安全。

StringBuilder线程不安全。

单线程操作,使用StringBuilder 效率高。

多线程操作,使用StringBuffer 安全。

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

       StringBuilder sb = new StringBuilder("abcdefg");

       sb.append("ak");  //abcdefgak

       sb.insert(1,"et");//aetbcdefg

       sb.deleteCharAt(2);//abdefg

        sb.delete(2,4);//abefg

       sb.setLength(4);//abcd

       sb.setCharAt(0,'k');//kbcdefg

       sb.replace(0,2,"hhhh");//hhhhcdefg

      

//想要使用缓冲区,先要建立对象。

       StringBuffer sb = new StringBuffer();    

       sb.append(12).append("haha");//方法调用链。

       String s = "abc"+4+'q';

       s = new StringBuffer().append("abc").append(4).append('q').toString();

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

class  Test{

    public static void main(String[] args) {

       String s1 = "java";

       String s2 = "hello";

       method_1(s1,s2);

       System.out.println(s1+"...."+s2); //java....hello

      

       StringBuilder s11 = new StringBuilder("java");

       StringBuilder s22 = new StringBuilder("hello");

       method_2(s11,s22);

       System.out.println(s11+"-----"+s22); //javahello-----hello

    }

    public static void method_1(String s1,String s2){

       s1.replace('a','k');

       s1 = s2;

    }

    public static void method_2(StringBuilder s1,StringBuilder s2){

       s1.append(s2);

       s1 = s2;

    }

}

集合框架:★★★★★,用于存储数据的容器。

特点:

1:对象封装数据,对象多了也需要存储。集合用于存储对象。

2:对象的个数确定可以使用数组,但是不确定怎么办?可以用集合。因为集合是可变长度的。

集合和数组的区别:

1:数组是固定长度的;集合可变长度的。

2:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。

3:数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

数据结构:就是容器中存储数据的方式。

对于集合容器,有很多种。因为每一个容器的自身特点不同,其实原理在于每个容器的内部数据结构不同。

集合容器在不断向上抽取过程中。出现了集合体系。

在使用一个体系时,原则:参阅顶层内容。建立底层对象。

--< java.util >-- List接口:

List本身是Collection接口的子接口,具备了Collection的所有方法。现在学习List体系特有的共性方法,查阅方法发现List的特有方法都有索引,这是该集合最大的特点。

List有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。

    |--ArrayList底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。

    |--LinkedList底层的数据结构是链表,线程不同步,增删元素的速度非常快。

    |--Vector底层的数据结构就是数组,线程同步的,Vector无论查询和增删都巨慢。

1,添加:

    add(index,element) :在指定的索引位插入元素。

    addAll(index,collection) :在指定的索引位插入一堆元素。

2,删除:

    remove(index) :删除指定索引位的元素。 返回被删的元素。

3,获取:

    Object get(index) :通过索引获取指定元素。

    int indexOf(obj) :获取指定元素第一次出现的索引位,如果该元素不存在返回-1;

                    所以,通过-1,可以判断一个元素是否存在。

    int lastIndexOf(Object o) :反向索引指定元素的位置。

    List subList(start,end) :获取子列表。

4,修改:

    Object set(index,element) :对指定索引位进行元素的修改。

5,获取所有元素:

    ListIterator listIterator():list集合特有的迭代器。

List集合支持对元素的增、删、改、查。

List集合因为角标有了自己的获取元素的方式: 遍历。

for(int x=0; x<list.size(); x++){

  sop("get:"+list.get(x));

}

在进行list列表元素迭代的时候,如果想要在迭代过程中,想要对元素进行操作的时候,比如满足条件添加新元素。会发生.ConcurrentModificationException并发修改异常。

导致的原因是:

集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。

如何解决呢?

既然是在迭代中对元素进行操作,找迭代器的方法最为合适.可是Iterator中只有hasNext,next,remove方法.通过查阅的它的子接口,ListIterator,发现该列表迭代器接口具备了对元素的增、删、改、查的动作。

--< java.util >-- Set接口

Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一种,迭代器。

  |--HashSet底层数据结构是哈希表,线程是不同步的。无序,高效;

     HashSet集合保证元素唯一性:通过元素的hashCode方法,和equals方法完成的。

     当元素的hashCode值相同时,才继续判断元素的equals是否为true。

     如果为true,那么视为相同元素,不存。如果为false,那么存储。

     如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。

      |--LinkedHashSet有序,hashset的子类。

  |--TreeSet对Set集合中的元素的进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。

哈希表的原理:

1,对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。

2,哈希值就是这个元素的位置。

3,如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。

4,存储哈希值的结构,我们称为哈希表。

5,既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。

  这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。

对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。

对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。

TreeSet:

  用于对Set集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性。

  如果元素不具备比较性,在运行时会发生ClassCastException异常。

  所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。

  依据compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。

  TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存。

注意:在进行比较时,如果判断元素不唯一,比如,同姓名,同年龄,才视为同一个人。

  在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。

TreeSet集合排序有两种方式,Comparable和Comparator区别:

1:让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法。

2:让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。

第二种方式较为灵活。

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

Map集合:

|--Hashtable底层是哈希表数据结构,是线程同步的。不可以存储null键,null值。

|--HashMap底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable.

|--TreeMap底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。

Map集合存储和Collection有着很大不同:

Collection一次存一个元素;Map一次存一对元素。

Collection是单列集合;Map是双列集合。

Map中的存储的一对元素:一个是键,一个是值,键与值之间有对应(映射)关系。

特点:要保证map集合中键的唯一性。

1,添加。

 put(key,value):当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。

  void putAll(Map);

2,删除。

  void clear():清空

  value remove(key) :删除指定键。

3,判断。

  boolean isEmpty()

  boolean containsKey(key):是否包含key

  boolean containsValue(value) :是否包含value

4,取出。

  int size():返回长度

  value get(key) :通过指定键获取对应的值。如果返回null,可以判断该键不存在。当然有特殊情况,就是在hashmap集合中,是可以存储null键null值的。

  Collection values():获取map集合中的所有的值。

5,想要获取map中的所有元素:

  原理:map中是没有迭代器的,collection具备迭代器,只要将map集合转成Set集合,可以使用迭代器了。之所以转成set,是因为map集合具备着键的唯一性,其实set集合就来自于map,set集合底层其实用的就是map的方法。

把map集合转成set的方法:

Set keySet();

Set entrySet();//取的是键和值的映射关系。

Entry就是Map接口中的内部接口;

为什么要定义在map内部呢?entry是访问键值关系的入口,是map的入口,访问的是map中的键值对。

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

取出map集合中所有元素的方式一:keySet()方法。

可以将map集合中的键都取出存放到set集合中。对set集合进行迭代。迭代完成,再通过get方法对获取到的键进行值的获取。

     Set keySet = map.keySet();

     Iterator it = keySet.iterator();

     while(it.hasNext()) {

         Object key = it.next();

         Object value = map.get(key);

         System.out.println(key+":"+value);

     }

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

取出map集合中所有元素的方式二:entrySet()方法。

Set entrySet = map.entrySet();

       Iterator it = entrySet.iterator();

       while(it.hasNext()) {

           Map.Entry  me = (Map.Entry)it.next();

           System.out.println(me.getKey()+"::::"+me.getValue());

       }

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

使用集合的技巧:

看到Array就是数组结构,有角标,查询速度很快。

看到link就是链表结构:增删速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();

看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。

看到tree就是二叉树,就要想到排序,就想要用到比较。

比较的两种方式:

一个是Comparable:覆盖compareTo方法;

一个是Comparator:覆盖compare方法。

LinkedHashSet,LinkedHashMap:这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。

集合什么时候用?

当存储的是一个元素时,就用Collection。当存储对象之间存在着映射关系时,就使用Map集合。

保证唯一,就用Set。不保证唯一,就用List。

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

Collections它的出现给集合操作提供了更多的功能。这个类不需要创建对象,内部提供的都是静态方法。

静态方法:

Collections.sort(list);//list集合进行元素的自然顺序排序。

Collections.sort(list,new ComparatorByLen());//按指定的比较器方法排序。

class ComparatorByLen implements Comparator<String>{

  public int compare(String s1,String s2){

     int temp = s1.length()-s2.length();

     return temp==0?s1.compareTo(s2):temp;

  }

}

Collections.max(list); //返回list中字典顺序最大的元素。

int index = Collections.binarySearch(list,"zz");//二分查找,返回角标。

Collections.reverseOrder();//逆向反转排序。

Collections.shuffle(list);//随机对list中的元素进行位置的置换。

将非同步集合转成同步集合的方法:Collections中的  XXX synchronizedXXX(XXX);

List synchronizedList(list);

Map synchronizedMap(map);

原理:定义一个类,将集合所有的方法加同一把锁后返回。

Collection 和 Collections的区别:

Collections是个java.util下的类,是针对集合类的一个工具类,提供一系列静态方法,实现对集合的查找、排序、替换、线程安全化(将非同步的集合转换成同步的)等操作。

Collection是个java.util下的接口,它是各种集合结构的父接口,继承于它的接口主要有Set和List,提供了关于集合的一些操作,如插入、删除、判断一个元素是否其成员、遍历等。

API--- java.util.Math: 用于数学运算的工具类,属性和行为都是静态的。该类是final不允许继承。

static double ceil(double a) ; //返回大于指定数值的最小整数

static double floor(double a) ; //返回小于指定数值的最大整数

static long round(double a) ; //四舍五入成整数

static double pow(double a, double b) ; //a的b次幂

static double random(); //返回0~1的伪随机数

    public static void main(String[] args) {

       Random r = new Random();

       for(int x=0; x<10; x++) {

           //double d = Math.floor(Math.random()*10+1);

           //int d  = (int)(Math.random()*10+1);

           int d = r.nextInt(10)+1;

           System.out.println(d);

       }

    }

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

API--- java.util.Date日期类,月份从0-11;

    /*

    日期对象和毫秒值之间的转换。

    1,日期对象转成毫秒值。Date类中的getTime方法。

    2,如何将获取到的毫秒值转成具体的日期呢?

       Date类中的setTime方法。也可以通过构造函数。

    */

       //日期对象转成毫秒值

       Date d = new Date();

       long time1 = d.getTime();

       long time2 = System.currentTimeMillis(); / /毫秒值。

      

       //毫秒值转成具体的日期

       long time = 1322709921312l;

       Date d = new Date();

       d.setTime(time);

/*

    将日期字符串转换成日期对象:使用的就是DateFormat方法中的  Date parse(String source) ;

    */

    public static void method() throws Exception {

       String str_time = "2011/10/25";

       DateFormat df = new SimpleDateFormat("yyyy/MM/dd"); //SimpleDateFormat作为可以指定用户自定义的格式来完成格式化。

       Date d = df.parse(str_time);

    }

    /*

    如果不需要使用特定的格式化风格,完全可以使用DateFormat类中的静态工厂方法获取具体的已经封装好风格的对象。getDateInstance();getDateTimeInstance();

    */

       Date d = new Date();

       DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);

       df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);

       String str_time = df.format(d);

    //将日期对象转换成字符串的方式:DateFormat类中的format方法。

        //创建日期格式对象。

       DateFormat df = new SimpleDateFormat(); //该对象的建立内部会封装一个默认的日期格式。11-12-1 下午1:48

       //如果想要自定义日期格式的话。可使用SimpleDateFormat的构造函数。将具体的格式作为参数传入到构造函数中。如何表示日期中年的部分呢?可以必须要参与格式对象文档。

       df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

       //调用DateFormat中的format方法。对已有的日期对象进行格式化。

       String str_time = df.format(d);

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

API--- java.util. Calendar日历类

    public static void method(){

       Calendar c = Calendar.getInstance();

       System.out.println(c.get(Calendar.YEAR)+"年"+(c.get(Calendar.MONTH)+1)+"月"

                     +getNum(c.get(Calendar.DAY_OF_MONTH))+"日"

                     +"星期"+getWeek(c.get(Calendar.DAY_OF_WEEK)));

    }

    public static String getNum(int num){

       return num>9 ? num+"" : "0"+num;

    }

    public static String getWeek(int index){

    /*

    查表法:建立数据的对应关系.

    最好:数据个数是确定的,而且有对应关系。如果对应关系的一方,是数字,而且可以作为角标,那么可以通过数组来作为表。

    */

       String[] weeks = {"","日","一","二","三","四","五","六"};

       return weeks[index];

    }

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

IO流:★★★★★,用于处理设备上数据。

流:可以理解数据的流动,就是一个数据流。IO流最终要以对象来体现,对象都存在IO包中。

流也进行分类:

1:输入流(读)和输出流(写)。

2:因为处理的数据不同,分为字节流和字符流。

字节流:处理字节数据的流对象。设备上的数据无论是图片或者dvd,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。

那么为什么要有字符流呢?因为字符每个国家都不一样,所以涉及到了字符编码问题,那么GBK编码的中文用unicode编码解析是有问题的,所以需要获取中文字节数据的同时+ 指定的编码表才可以解析正确数据。为了方便于文字的解析,所以将字节流和编码表封装成对象,这个对象就是字符流。只要操作字符数据,优先考虑使用字符流体系。

注意:流的操作只有两种:读和写。

流的体系因为功能不同,但是有共性内容,不断抽取,形成继承体系。该体系一共有四个基类,而且都是抽象类。

字节流:InputStream  OutputStream

字符流:Reader  Writer

在这四个系统中,它们的子类,都有一个共性特点:子类名后缀都是父类名,前缀名都是这个子类的功能名称。

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

IO中的使用到了一个设计模式:装饰设计模式。

装饰设计模式解决:对一组类进行功能的增强。

包装:写一个类(包装类)对被包装对象进行包装;

 * 1、包装类和被包装对象要实现同样的接口;

 * 2、包装类要持有一个被包装对象;

 * 3、包装类在实现接口时,大部分方法是靠调用被包装对象来实现的,对于需要修改的方法我们自己实现;

网络编程:

端口:

物理端口:

逻辑端口:用于标识进程的逻辑地址,不同进程的标识;有效端口:0~65535,其中0~1024系统使用或保留端口。

java 中ip对象:InetAddress.

import java.net.*;

class  IPDemo{

    public static void main(String[] args) throws UnknownHostException{

       //通过名称(ip字符串or主机名)来获取一个ip对象。

       InetAddress ip = InetAddress.getByName("www.baidu.com");//java.net.UnknownHostException

       System.out.println("addr:"+ip.getHostAddress());

       System.out.println("name:"+ip.getHostName());

    }

}

Socket:★★★★,套接字,通信的端点

就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。

UDP传输:

1,只要是网络传输,必须有socket 。

2,数据一定要封装到数据包中,数据包中包括目的地址、端口、数据等信息。

直接操作udp不可能,对于java语言应该将udp封装成对象,易于我们的使用,这个对象就是DatagramSocket. 封装了udp传输协议的socket对象。

因为数据包中包含的信息较多,为了操作这些信息方便,也一样会将其封装成对象。这个数据包对象就是:DatagramPacket.通过这个对象中的方法,就可以获取到数据包中的各种信息。

DatagramSocket具备发送和接受功能,在进行udp传输时,需要明确一个是发送端,一个是接收端。

udp的发送端:

1,建立udp的socket服务,创建对象时如果没有明确端口,系统会自动分配一个未被使用的端口。

2,明确要发送的具体数据。

3,将数据封装成了数据包。

4,用socket服务的send方法将数据包发送出去。

5,关闭资源。

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

import java.net.*;

class  UdpSend{

    public static void main(String[] args)throws Exception {

//     1,建立udp的socket服务。

       DatagramSocket ds = new DatagramSocket(8888);//指定发送端口,不指定系统会随机分配。

//     2,明确要发送的具体数据。

       String text = "udp传输演示 哥们来了";

       byte[] buf = text.getBytes();

//     3,将数据封装成了数据包。

       DatagramPacket dp = new DatagramPacket(buf,

buf.length,InetAddress.getByName("10.1.31.127"),10000);

//     4,用socket服务的send方法将数据包发送出去。

       ds.send(dp);

//     5,关闭资源。

       ds.close();

    }

}

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

udp的接收端:

1,创建udp的socket服务,必须要明确一个端口,作用在于,只有发送到这个端口的数据才是这个接收端可以处理的数据。

2,定义数据包,用于存储接收到数据。

3,通过socket服务的接收方法将收到的数据存储到数据包中。

4,通过数据包的方法获取数据包中的具体数据内容,比如ip、端口、数据等等。

5,关闭资源。

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

class UdpRece {

    public static void main(String[] args) throws Exception{

//     1,创建udp的socket服务。

       DatagramSocket ds = new DatagramSocket(10000);

//     2,定义数据包,用于存储接收到数据。先定义字节数组,数据包会把数据存储到字节数组中。

       byte[] buf = new byte[1024];

       DatagramPacket dp = new DatagramPacket(buf,buf.length);

//     3,通过socket服务的接收方法将收到的数据存储到数据包中。

       ds.receive(dp);//该方法是阻塞式方法。

//     4,通过数据包的方法获取数据包中的具体数据内容,比如ip,端口,数据等等。

       String ip = dp.getAddress().getHostAddress();

       int port = dp.getPort();

       String text = new String(dp.getData(),0,dp.getLength());//将字节数组中的有效部分转成字符串。

       System.out.println(ip+":"+port+"--"+text);

//     5,关闭资源。

       ds.close();

    }

}

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

TCP传输:两个端点的建立连接后会有一个传输数据的通道,这通道称为流,而且是建立在网络基础上的流,称之为socket流。该流中既有读取,也有写入。

tcp的两个端点:一个是客户端,一个是服务端。

客户端:对应的对象,Socket

服务端:对应的对象,ServerSocket

TCP客户端:

1,建立tcp的socket服务,最好明确具体的地址和端口。这个对象在创建时,就已经可以对指定ip和端口进行连接(三次握手)。

2,如果连接成功,就意味着通道建立了,socket流就已经产生了。只要获取到socket流中的读取流和写入流即可,只要通过getInputStream和getOutputStream就可以获取两个流对象。

3,关闭资源。

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

import java.net.*;

import java.io.*;

//需求:客户端给服务器端发送一个数据。

class  TcpClient{

    public static void main(String[] args) throws Exception{

       Socket s = new Socket("10.1.31.69",10002);

        OutputStream out = s.getOutputStream();//获取了socket流中的输出流对象。

       out.write("tcp演示,哥们又来了!".getBytes());

       s.close();

    }

}

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

TCP服务端:

1,创建服务端socket服务,并监听一个端口。

2,服务端为了给客户端提供服务,获取客户端的内容,可以通过accept方法获取连接过来的客户端对象。

3,可以通过获取到的socket对象中的socket流和具体的客户端进行通讯。

4,如果通讯结束,关闭资源。注意:要先关客户端,再关服务端。

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

class  TcpServer{

    public static void main(String[] args) throws Exception{

       ServerSocket ss = new ServerSocket(10002);//建立服务端的socket服务

       Socket s = ss.accept();//获取客户端对象

       String ip = s.getInetAddress().getHostAddress();

       System.out.println(ip+".....connected");

//     可以通过获取到的socket对象中的socket流和具体的客户端进行通讯。

       InputStream in = s.getInputStream();//读取客户端的数据,使用客户端对象的socket读取流

       byte[] buf = new byte[1024];

       int len = in.read(buf);

       String text = new String(buf,0,len);

       System.out.println(text);

//     如果通讯结束,关闭资源。注意:要先关客户端,在关服务端。

       s.close();

       ss.close();

    }

}

反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。

反射的好处:大大的增强了程序的扩展性。

反射的基本步骤:

1、获得Class对象,就是获取到指定的名称的字节码文件对象。

2、实例化对象,获得类的属性、方法或构造函数。

3、访问属性、调用方法、调用构造函数创建对象。

获取这个Class对象,有三种方式:

1:通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。

2:每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。

     前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。

3:使用的Class类中的方法,静态的forName方法。

     指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。

// 1. 根据给定的类名来获得  用于类加载

String classname = "cn.itcast.reflect.Person";// 来自配置文件

Class clazz = Class.forName(classname);// 此对象代表Person.class

// 2. 如果拿到了对象,不知道是什么类型   用于获得对象的类型

Object obj = new Person();

Class clazz1 = obj.getClass();// 获得对象具体的类型

// 3. 如果是明确地获得某个类的Class对象  主要用于传参

Class clazz2 = Person.class; 

反射的用法

1)、需要获得java类的各个组成部分,首先需要获得类的Class对象,获得Class对象的三种方式:

    Class.forName(classname) 用于做类加载

    obj.getClass()              用于获得对象的类型

    类名.class            用于获得指定的类型,传参用

2)、反射类的成员方法:

    Class clazz = Person.class;

    Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});

    method.invoke();

   

3)、反射类的构造函数:

    Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})

    con.newInstance(params...)

4)、反射类的属性:

    Field field = clazz.getField(fieldName);

    field.setAccessible(true);

    field.setObject(value);

获取了字节码文件对象后,最终都需要创建指定类的对象:

创建对象的两种方式(其实就是对象在进行实例化时的初始化方式):

1,调用空参数的构造函数:使用了Class类中的newInstance()方法。

2,调用带参数的构造函数:先要获取指定参数列表的构造函数对象,然后通过该构造函数的对象的newInstance(实际参数) 进行对象的初始化。

综上所述,第二种方式,必须要先明确具体的构造函数的参数类型,不便于扩展。所以一般情况下,被反射的类,内部通常都会提供一个公有的空参数的构造函数。

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

    // 如何生成获取到字节码文件对象的实例对象。

       Class clazz = Class.forName("cn.itcast.bean.Person");//类加载

// 直接获得指定的类型

       clazz = Person.class;

       // 根据对象获得类型

       Object obj = new Person("zhangsan", 19);

       clazz = obj.getClass();

      Object obj = clazz.newInstance();//该实例化对象的方法调用就是指定类中的空参数构造函数,给创建对象进行初始化。当指定类中没有空参数构造函数时,该如何创建该类对象呢?请看method_2();

    public static void method_2() throws Exception {

       Class clazz = Class.forName("cn.itcast.bean.Person");

       //既然类中没有空参数的构造函数,那么只有获取指定参数的构造函数,用该函数来进行实例化。

       //获取一个带参数的构造器。

       Constructor constructor = clazz.getConstructor(String.class,int.class);

       //想要对对象进行初始化,使用构造器的方法newInstance();

       Object obj = constructor.newInstance("zhagnsan",30);

       //获取所有构造器。

       Constructor[] constructors = clazz.getConstructors();//只包含公共的

       constructors = clazz.getDeclaredConstructors();//包含私有的

       for(Constructor con : constructors) {

           System.out.println(con);

       }

    }

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

反射指定类中的方法:

    //获取类中所有的方法。

    public static void method_1() throws Exception {

       Class clazz = Class.forName("cn.itcast.bean.Person");

       Method[] methods = clazz.getMethods();//获取的是该类中的公有方法和父类中的公有方法。

       methods = clazz.getDeclaredMethods();//获取本类中的方法,包含私有方法。

       for(Method method : methods) {

           System.out.println(method);

       }

    }

    //获取指定方法;

    public static void method_2() throws Exception {

       Class clazz = Class.forName("cn.itcast.bean.Person");

       //获取指定名称的方法。

       Method method = clazz.getMethod("show", int.class,String.class);

       //想要运行指定方法,当然是方法对象最清楚,为了让方法运行,调用方法对象的invoke方法即可,但是方法运行必须要明确所属的对象和具体的实际参数。

       Object obj = clazz.newInstance();

       method.invoke(obj, 39,"hehehe");//执行一个方法

    }

    //想要运行私有方法。

    public static void method_3() throws Exception {

       Class clazz = Class.forName("cn.itcast.bean.Person");

       //想要获取私有方法。必须用getDeclearMethod();

       Method method = clazz.getDeclaredMethod("method", null);

       // 私有方法不能直接访问,因为权限不够。非要访问,可以通过暴力的方式。

       method.setAccessible(true);//一般很少用,因为私有就是隐藏起来,所以尽量不要访问。

    }

    //反射静态方法。

    public static void method_4() throws Exception {

       Class clazz = Class.forName("cn.itcast.bean.Person");

       Method method = clazz.getMethod("function",null);

       method.invoke(null,null);

    }

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

正则表达式:★★★☆,其实是用来操作字符串的一些规则。

好处:正则的出现,对字符串的复杂操作变得更为简单。

特点:将对字符串操作的代码用一些符号来表示。只要使用了指定符号,就可以调用底层的代码对字符串进行操作。符号的出现,简化了代码的书写。

弊端:符号的出现虽然简化了书写,但是却降低了阅读性。

其实更多是用正则解决字符串操作的问题。

组:用小括号标示,每定义一个小括号,就是一个组,而且有自动编号,从1开始。

    只要使用组,对应的数字就是使用该组的内容。别忘了,数组要加\\。

    (aaa(wwww(ccc))(eee))技巧,从左括号开始数即可。有几个左括号就是几组。

常见操作:

1,匹配:其实用的就是String类中的matches方法。

String reg = "[1-9][0-9]{4,14}";

    boolean b = qq.matches(reg);//将正则和字符串关联对字符串进行匹配。

2,切割:其实用的就是String类中的split方法。

3,替换:其实用的就是String类中的replaceAll();

4,获取:

   1),先要将正则表达式编译成正则对象。使用的是Pattern中静态方法 compile(regex);

   2),通过Pattern对象获取Matcher对象。

      Pattern用于描述正则表达式,可以对正则表达式进行解析。

      而将规则操作字符串,需要从新封装到匹配器对象Matcher中。

      然后使用Matcher对象的方法来操作字符串。

      如何获取匹配器对象呢?

      通过Pattern对象中的matcher方法。该方法可以正则规则和字符串想关联。并返回匹配器对象。

   3),使用Matcher对象中的方法即可对字符串进行各种正则操作。

  Servlet 

Servlet工作原理

Servlet有支持servlet的服务器:servlet引擎,负责管理运行.当多个客户请求一个servlet时,引擎为每个客户启动一个线程而不是启动一个进程,这些线程由Servlet引擎服务器负责管理,与传统的CGI为每个客户启动一个进程相比较,效率要搞的多

Servlet的生命周期

(1)初始化Servlet。Servlet第一次呗请求加载时。服务器初始化这个Servlet,即创建一个Servlet对象,这对象调用init方法完成必要的初始化工作

(2)诞生的Servlet对象在调用Servlet方法响应客户的请求

(3)当服务器关闭时,调用destroy方法,消灭Servlet对象

init方法只能被调用一次,即在Servlet第一次请求加载时调用该方法。当后续的客户请求Servlet服务时,web服务将启动一个新的线程,该线程中,servlet调用service方法响应客户的请求,也就是说,每个客户的每次请求都导致service方法被调用执行

init方法

调用者:Tomcat等web服务器(web容器,servlet容器)

执行次数:一次

执行时间:默认情况:第一次请求的开始,肯定在service方法之前

          配置,在服务器启动时执行

           <servlet>

          <load-on-startup>0</load-on-startup>

           配置当前 servlet在服务器启动时执行init方法

             取值:整型,(0 ## 7)数字越小,优先初始化

servlet第一次被请求加载时,服务器初始化一个servlet,即创建一个servlet对象,这个对象调用init方法完成必要的初始化工作。该方法在执行时,servlet引擎会把一个

SevletConfig类型的对象传递给init()方法,这个对象就被保存在servlet对象中,直到servlet对象被消灭,这个ServletConfig对象负责向servlet传递服务设置信息,如果传递失败就会发生ServeletException,servlet就不能正常工作。

service方法

当servlet成功创建和初始化之后,servlet就调用service方法来处理用户的请求并返回响应。servlet引擎将两个参数传递给该方法,一个HttpServletRequest类型的对象,该对象封装了用户的请求信息,次对象调用相应的方法获取封装的信息,即使用这个对象可以获取用户提交的信息。另外一个参数对象是HttpServletResponse类型的对象,该对象用来响应用户的请求。和init方法不同的是,init方法只被调用一次,而service方法可能被多次调用,当后续的客户请求servlet服务时,servlet引擎将启动一个新的线程,在该线程中,servlet调用service方法响应客户的请求,也就是说,每个客户的每次请求都导致service呗调用执行,调用的过程运行在不同的线程中,互不干扰

destory方法

当servlet引擎服务器终止服务时,比如关闭服务器,destory()方法会被执行,消灭servlet对象

Servlet的优点

可移植性(Portability)
Servlet 皆是利用Java 语言来开发的,因此,延续Java 在跨平台上的表现,不论Server 的操作系统是Windows、Solaris、Linux、HP-UX、FreeBSD、Compaq Tru 64、AIX 等等,都能够将我们所写好的Servlet程序放在这些操作系统上执行。借助Servlet的优势,就可以真正达到Write Once, Serve Anywhere 的境界,这正是从事Java 程序员最感到欣慰也是最骄傲的地方。当程序员在开发Applet 时,时常为了“可移植性”(portability)让程序员感到绑手绑脚的,例如:开发Applet 时,为了配合Client端的平台( 即浏览器版本的不同,plug-in 的JDK版本也不尽相同 ),达到满足真正“跨平台”的目的时,需要花费程序员大量时间来修改程序,为的就是能够让用户皆能够执行。但即使如此,往往也只能满足大部分用户,而其他少数用户,若要执行Applet,仍须先安装合适的JRE (Java Runtime Environment)。
但是Servlet 就不同了,主要原因在于Servlet 是在Server 端上执行的,所以,程序员只要专心开发能在实际应用的平台环境下测试无误即可。除非你是从事做Servlet Container 的公司,否则不须担心写出来的Servlet 是否能在所有的Java Server 平台上执行。
● 强大的功能

Servlet 能够完全发挥Java API 的威力,包括网络和URL 存取、多线程(Multi-Thread)、影像处理、RMI (Remote Method Invocation)、分布式服务器组件 (Enterprise Java Bean)、对象序列化 (Object Serialization) 等。若想写个网络目录查询程序,则可利用JNDI API;想连接数据库,则可利用JDBC,有这些强大功能的API 做后盾,相信Servlet 更能够发挥其优势。
● 性能

Servlet 在加载执行之后,其对象实体(instance)通常会一直停留在Server 的内存中,若有请
求(request)发生时,服务器再调用Servlet 来服务,假若收到相同服务的请求时,Servlet会利用不同的线程来处理,不像CGI 程序必须产生许多进程 (process)来处理数据。在性能的表现上,大大超越以往撰写的CGI 程序。最后补充一点,那就是Servlet 在执行时,不是一直停留在内存中,服务器会自动将停留时间过长一直没有执行的Servlet 从内存中移除,不过有时候也可以自行写程序来控制。至于停留时间的长短通常和选用的服务器有关。
● 安全性
Servlet也有类型检查(Type Checking)的特性,并且利用Java的垃圾收集(Garbage Collection)
与没有指针的设计,使得Servlet 避免内存管理的问题。由于在Java的异常处理(Exception-Handling)机制下,Servlet能够安全地处理各种错误,不会因为发生程序上逻辑错误而导致整体服务器系统的毁灭。例如:某个Servlet发生除以零或其他不合法的运算时,它会抛出一个异常(Exception)让服务器处理,如:记录在记录文件中(log file)。

更多相关推荐:
Java总结

Java总结Java语言不允许程序员直接控制内存空间的使用。内存空间的分配和回收是有jre负责在后台自动进行,尤其是无用内存空间的回收操作。垃圾回收器不可以被强制执行,但程序员可以通过调用system.gc()…

Java总结

Java总结一.1.Java程序的执行Java先由.Java文件编译生成.class文件,再由.class文件通过不同操作系统的虚拟机进行解释从而执行程序结果。编译命令:javac+文件名.Java解释命令:j…

JAVA总结

1.构造函数:是一种特殊的函数,没有返回值。构造函数的名称与类的名称相同。一般用于初始化成员变量的值。使用super关键字来调用父类的构造函数。2.方法的重载:法名相同但参数的个数或类型不同,一般情况下是在一个…

二级JAVA总结

对长度为n的线性表进行冒泡排序,最坏情况先需要比较的次数为log2n。对长度为n的线性表进行顺序排序,最坏情况先需要比较的次数为n。高内聚低耦合有利于模块的独立性。二叉树属于非线性结构。算法具有可行性、确定性、…

java总结

个人介绍:1.名字可以不用介绍;2.×××大学,学了什么(大致介绍)3.如何进入第一家公司;4.工作年限;5.大致讲下在公司所作的项目;技术方面:1.抽象类与接口的区别;2.版本控制(CVS,VSS)3.常用的…

JAVA总结

在这忙忙碌碌的这段时间里,经过老师的辅导,迅速的将一点没有学的JAVA基础搞定了!有了基础学习还是好,万事开头难这句话说的太对了,学计算机语言我觉得记忆好的方法就是多打代码,课前预习,课堂上认真听讲,把现学的方…

java总结

1.读入数据用Scanner2.向文件写数据用PrintWriter3.this.dispose();这个方法可以真正在内存中移除JFrame从类java.awt.Window继承的方法:dispose()pu…

毕向东java基础总结(完整版)

克己宽容仁德博学厚黑坚毅稳重Java基础知识总结168克己宽容仁德博学厚黑坚毅稳重Java基础知识总结超级经典写代码1明确需求我要做什么2分析思路我要怎么做1233确定步骤每一个思路部分用到哪些语句方法和对象4...

java面向对象总结

面向对象面向对象是一种思想能让复杂的问题简单化让我们角色从执行者变成指挥者不要知道过程只要知道结果一切皆对象描述一个事物其实就是在描述事物的属性和行为对象的特点在于封装数据数据包含着属性和行为我们用类来描述一个...

Java关键字总结

Java关键字总结21abstractJava关键字abstract关键字可以修改类或方法abstract类可以扩展增加子类但不能直接实例化abstract方法不在声明它的类中实现但必须在某个子类中重写示例pu...

java经典总结(超级经典)

java经典总结超级经典写代码1明确需求我要做什么2分析思路我要怎么做1233确定步骤每一个思路部分用到哪些语句方法和对象4代码实现用具体的java语言代码把思路体现出来学习新技术的四点1该技术是什么2该技术有...

java基础总结(上)

配置java环境变量JAVAHOME配置JDK的目录CLASSPATH指定到哪里去找运行时需要用到的类代码字节码PATH指定可执行程序的位置LINUX系统在quotbashprofilequot下的环境变量设置...

java总结(59篇)