java基础学习

java是面向对象的编程语言,面向对象的思想是:让复杂的问题简单话,角色从面向过程的执行者变为面向对象的指挥者。

一个例子,如:公司招聘你去干活,你就相当于一个对象,你会写代码,会测试等等,领导给你一个任务,他不需要知道你具体实现的细节,他只需要调用你会干活的功能就可以了,

他指挥你去做事情。

1.面向对象的三大特征:继承,封装,多态。

(1).类就是对现实事物的描述,对象是对这类事物中实实在在存在的实体,映射到java中,class定义的类,具体对象就是所对应的java在堆内存中new出来的实体。对象是存储某些具体的数据实体,是放在堆内存中,对于堆内存中的数据有默认初始化值得。

(2)描述事物就是在描述事物的一些行为和熟悉,其中,行为就是对应的方法,属性是对应的变量。定义类就是在定义属性和行为,属性和行为叫类的成员(成员分为成员变量和成员方法)

2.成员变量和局部变量

(1)作用服务:成员变量作用在整个类,局部变量作用在方法或语句中

(2)内存中的位置:成员变量在堆内存中,因为对象在堆内存中,局部变量在栈内存中。其中成员变量有默认初始化值,因为他在堆内存中,局部变量必须要有显示初始化值,否则不能参与运算。

3. 匿名对象:new Car().

匿名对象的使用

(1)当对象的方法只调用一次的时候,那么可以使用匿名对象,这样可以简化操作。(如果多次调用对象的方法,那么还是起个名字)

(2)可以将匿名对象作为实际参数进行传递。

4.封装

(1)指隐藏对象的属性和实现的细节,仅对外提供公共的访问方式

(2)好处,变化被隔离了,便于使用提高了代码的重用性,安全性。

(3)封装的原则:对不需要对外提供的内容隐藏起来,把属性隐藏起来,提供公共方法对其访问。

5.private

私有,权限修饰符,用于修饰类中的成员,私有只在本类中有用。

私有只是封装的一种表现形式,之所以要对外提供访问方式,因为可以在访问的方式中加上逻辑判断,对访问的数据进行操作,提高了代码的健壮性和安全性

6.构造函数

对象一建立就会调用与之对应的构造函数。

(1)构造函数的作用:用于给本类对象进行初始化的。每一个类中如果没有定义构造函数,那么就会调用其默认空参数构造函数,

当有了显示构造函数的时候,默认构造函数就不会调用了。

(2)构造函数和一般函数在写法上有所不同,构造函数是和类名相同的,而一般函数可以不一样。构造函数是对象一建立就运行是给对象进行初始化的,而一般函数是调用的时候才运行,是为了增加一些新的功能。一个构造函数在对象一建立就会被调用一次,而一般函数可以被对象调用多次。

(3)什么时候定义构造函数呢,当需要一些东西进行初始化的时候。

7.构造代码块

就是一个{code}区间。作用:给对象进行初始化,对象一建立就进行初始化,优先于构造函数进行初始化。

他和构造函数的区别:构造代码块是给所有对象进行统一初始化,构造函数是给某个具体对象进行初始化。

8.this

代表本类的对象,代表所在函数的所述对象的引用。简单的说,哪个对象在调用this所在的函数,this就代表哪个对象

(2)this的应用,当定义类中的功能时,该函数内部要用到调用函数该函数的对象时,这时候可以使用this,来表示本类对象。但凡本类功能使用了本类对象都用this表示。

(3)this语句,用于构造函数之间的调用。this语句只能在构造函数第一行,因为初始化操作要先执行,一般函数不能之间调用构造函数,因为this语句不能用在一个函数中

this的第二个作用是区别局部变量和成员变量重名情况。

9.static静态

用法,是一个修饰符可以用于修饰成员(成员变量和成员属性)

当成员被静态修饰之后就多了一个调用的方式,除了对象调用以外,还可以使用,。类名.静态成员

(2)static的特点

①随着类的加载而加载,类的消失而消失,说明他的生命周期长

②优先于对象存在,明确一点:静态先存在,对象后存在。

③被所有对象所共享

④可以直接被类名调用

(3)成员变量和类变量的区别

①存放位置:类变量随着对象的加载而加载存放在方法区中,成员变量在堆内存中

②生命周期:类变量生命周期最长,随着类的消失而消失

当类一被加载的时候静态就存在了,而对象这时还没有被创建,所以可以使用类名直接调用静态成员

特有内容随着对象的存在而在堆内存中

10.静态的使用注意事项

(1)静态只能访问静态成员,非静态既可以访问静态又可以访问访问非静态(因为静态优先于对象存在,所以后面可以访问后面的)

(2)静态方法中不可以出现this,super等关键字,因为静态先于对象存在

(3)main方法是静态的,它是一个特殊的方法,作用程序的入口。

11.静态的利弊

好处:对对象的共享数据进行存储,不必每个对象都存储一份,节省空间

坏处:生命周期长,访问出现局限性(静态虽好,只能访问静态)

12.什么时候需要使用静态

(1)因为静态修饰的内容有成员比变量和函数,当对象中出现共享数据的时候,该数据可以被静态所修饰,对象中的特有数据的话要定义为非静态的存在于堆内存中

(2)当功能内部没有访问到对象的特有数据的时候,可以将其定义为非静态。

13.一个类有一个默认的空参数的构造函数,这个默认的构造函数的权限和所属类是一致的,如果类被public修饰,那么默认的构造函数就有带public的修饰符,如果类没有被public修饰,那么默认的构造函数就没有public修饰

14.静态代码块 static{code}特点:随着类的加载而执行,只执行一次并优先于主函数,用于给类进行初始化。构造代码块是给所有对象进行初始化,构造函数是给具体对象进行初始化,它的执行顺序:静态代码块先执行,然后是构造代码块,最后是构造函数。

15.对象的初始化过程,Person p=new Person()。这句话做了什么

(1)因为new用到了Perso.class,所以先从硬盘中找到.class文件,通过jvm加载到内存中

(2)执行该类的静态代码块

(3)在堆内存中开辟空间,分配内存地址

(4)在堆内存中建立对象的特有属性,并进行默认初始化

(5)对对象的特有属性进行显示初始化

(6)对对象进行构造代码块初始化

(7)进行构造函数初始化

(8)对内存地址赋给栈内存中的P变量

16.设计模式:解决某一类问题有效的方法,java23种的设计模式,其中单例设计模式是解决一个类在内存中只存在一个对象的,保证对象的唯一性

(1)将构造函数私有化 private Single()

(2)在类中创建一个本类对象 private static Single s=new Single()

(3)提供一个方法可以获取该对象 public static Single getInstance(){return s}

注意:对于事物该怎么描述就怎么描述,当需要将事物的对象保证在内存中唯一时,将上面3步加上即可

17.单利设计模式中饿汉式和懒汉式。其中饿汉式是先进行初始化对象,以上就是一个饿汉式,Single类一进内存,就已经创建好对象了。

懒汉式是对象的方法被调用的时候才进行初始化,也叫对象的延迟加载,如:

(1)private static Single s=null;

(2)private Single(){}

(3)public static Single getInstance(){if(s==null)s=new Single() return s;}

原则上:在开发饿时候需要单例设计时,则定义为饿汉式。

18.继承

它提高了代码的复用性,让类与类之间有所属关系才可以继承,因为有了这个关系才有了多态的特性

java中只支持单继承,不支持多继承,因为多继承容易带来安全隐患,当多个父类中定义了相同的功能时,当功能不同时,子类对象不确定要运行哪一个,但是java保留了这种机制,并用另一种体现形式来完成:多态,如何使用一个继承体系中的功能?简单说:查阅父类功能,创建子类对象使用功能。

19.子父类之间成员特点
1.变量 。如果子父类中出现非私有的同名变量时,子类要访问本类中的变量时,用this,子类要访问父类中的同名变量时,需要使用super。this代表本类对象的引用,super代表父类的引用。

子父类中函数的特点-重写

注意:当父类方法的权限为private时,子类的权限大于其权限时,也不是重写,即使是相同的方法,因为父类的为private对外不提供访问权限

当子类出现和父类一样的函数时,当子类对象调用该函数,会运行子类函数的内容这就是重写。

(2)当子类继承父类,沿袭了父类的功能到子类中,这时,没有必要定义新的功能,而是子类虽具备该功能,但是功能的内容却和父类不一样。这时没有必要重新定义一个新的功能,而是使用重写,保留父类的功能定义。

(3)重写:子类覆盖父类工作,必须要保证子类权限大于等于父类权限,才可以覆盖,否则编译失败,静态只能覆盖静态

(4)说明:重载:函数名一样,参数列表不一样,返回值可以不一样。重写:子父类中方法一模一样。

20.子父类中的构造函数

当父类中没有空参数的构造函数时,那么子类必须手动写带有参数列表的super语句且在构造函数中第一行。

(2)this语句和super语句为什么不能同时出现在构造函数中,因为它们都必须在第一行,而为什么要在第一行呢,因为初始化操作要先执行。

(3)在子类对象进行初始化时,父类的构造函数也会执行,因为子类构造函数默认第一行有个隐式的super()语句用来调用父类中空参数的构造函数。

(4)为什么子类一定要访问父类中的构造函数?因为子类需要用到父类中的数据,所以子类对象在建立的时候会先去看父类是如何进行数据初始化的,如果要访问父类指定的构造函数,那么就需要用super语句来指定。

(5)子类的实例化过程

子类中所有的构造函数默认都会访问父类中空参数的构造函数,因为子类中的构造函数第一行有个隐式的super语句。当父类中没有空参数的构造函数时,子类必须手动通过super语句来指定需要访问的构造函数,当然子类中的构造函数第一行也可以手动的指定this语句来访问本类中的构造函数,子类中至少有一个构造函数会访问父类中的构造函数。

21.final关键字,表示最终作为一个修饰符

(1)可以修饰类,变量,函数。

(2)被final修饰的类不可以被继承,为了避免被继承被子类重写

(3)被final修饰的方法不可以被重写

(4)被final修饰的变量,相当于一个常量,只能赋值一次。

(5)内部类定义在类中的局部位置上,只能访问该局部被final修饰的局部变量

22.抽象

当多个类中出现相同功能,但是功能的内容不同,功能的名称一样,那么就可以向上抽取,这时只抽取功能定义,而不能抽取功能主题,抽象类的特点:

(1)抽象方法一定在抽象类中

(2)抽象方法和抽象类都必须被abstract修饰

(3)抽象类不可以被new创建对象,因为调用抽象方法没有意义。

(4)抽象类中方法要被使用,必须有子类重写所有的抽象方法,如果子类只覆盖了部分的抽象方法,那么该类还是一个抽象类

(5)抽象类中可以有抽象方法和非抽象方法。

23.模板设计模式:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分需要使用不确定的部分,那么就将不确定的部分暴露出去,有子类去完成,例如获取某代码的执行时间、abstract class GetTime{public void getTm(){long start =System.currentTimeMills(); runcode(); long end=System.currentTimeMills() ; long result= end - start;} public abstract void runcode();}

23.接口

当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示

(2)接口的特点

接口中常见的定义:常量,抽象方法。

接口中的成员都有固定修饰符,其中常量 public static final ,方法 public,记住:接口中的成员都是public修饰权限

接口是不可以创建对象的,需要子类去实现,子类对接口中的抽象方法全部都需要覆盖,子类才可以实例化。

接口可以被类多实现,也是对多继承不支持的一种转换,java中只有在接口与接口之间才支持多继承。

基本功能定义在继承中,附件功能定义在接口中。

24.多态

(1)多态的体现:父类的引用指向自己子类对象,父类的引用也可以接收自己的子类对象

(2)多态的前提,必须是类与类之间有关系,要么继承,要么实现,通常有一个前提:存在覆盖

(3)多态的好处:提高了代码的扩张性

(4)多态的弊端:只能使用父类的引用访问父类中的成员

25.多态的类型转换 Animal a=new Cat();类型提升,向上转型,如果想要调用猫的特有方法,可以强制将父类引用转成子类类型,向下转型。Cat c=(Cat) a

不要出现这样的操作,就是将父类的对象转成子类对类型,而我们可以做的就是将父类的引用指向自己子类对象,该引用可以提升,其实多态始终是子类对象做着变换。

26.在多态中非静态成员函数的特点

在编译时期,对于成员变量(非静态)的在多态调用时,编译看左边,运行看右边

在多态中成员变量和静态成员的特点:无论编译和运行都参考左边。

27.内部类。

(1)可以直接访问外部类中的成员,包括私有,之所以可以直接访问外部类中的成员,是因为内部类中有外部类的引用。格式:外部类名.this

(2)外部类要访问内部类,必须要建立内部类对象,直接访问内部类中的成员,可以这样(当内部类不是私有时)Outer.Inter in=new Outer().new Inter; in.method()

(3)类可以被私有化,当内部类在外部类的成员位置时,才可以进行私有化private访问。

28.内部类的访问格式

(1)当内部类定义在外部类成员位置上而且非私有,可以在外部其他类中可以直接建立内部类对象。格式:外部类名.内部类名 变量名=外部类对象.内部对象。如:

Outer.Inter in=new Outer().new Inter;

(2)当内部类定义了静态成员,该内部类必须是静态的。当外部类中的静态方法访问内部类时,内部内也必须是静态的

(3)当描述事物的时候,事物的内部还有事物,该事物用内部类描述,因为内部事物在使用外部事物的内容。

29.内部类定义在局部时

(1)不可以被成员修饰符所修饰

(2)可以直接访问外部内中的成员,因为有外部内的引用,但是不可以访问他所在的局部位置,只能访问被final修饰的局部变量。如:

void method(){final int y=7; class Inter{void function(){System.out.println(y);}} new Inter().function();}

30.匿名类部类

(1)匿名内部内其实就是内部类的简写格式

(2)定义匿名内部类的前提:内部类必须是继承一个类或者实现接口

(3)匿名内部类的格式:new 父类或者接口{定义子类的内容}

(4)匿名内部类中定义的方法最好不要超过3个,如:new AbsDemo(){void show(){systemout.println("fff")}}这就是一个匿名对象,其中AbsDemo是一个父类或接口,show为其里面的方法。

31.    异常

程序运行时出现不正常情况、

异常的由来: 问题也是一个具体的事物,也可以通过java类形式进行描述,并封装成对象。

对于严重的问题,java通过Error类进行描述,一般不针对性的处理。

对于非严重的问题,java通过Exception类进行描述。可以针对性的进行处理

Error和Exception都是Throwable的子类。

(2)异常的处理,java提供了特有的语句进行处理,try{需要被检测的代码}catch(异常类处理){处理异常的代码}finally{一定会执行的代码}

(3)对于捕获到的异常常见的处理方法如:getMessage将异常信息打印处理。

(4)功能上通过throws的关键字声明该功能有可能出现的问题

32.在函数上声明异常,便于提高安全性,让调用者进行处理,不处理那么会编译失败

对多异常的处理,就用对应几个catch块,如多个catch块中的异常出现继承关系,那么父类异常要放到最下面,所对应的catch块要声明更为具体的异常

建议在进行catch处理时,catch中一定要定义具体处理方式,不要简单的就输出了。

函数中没有处理异常的情况只要发生异常,那么该函数就会停止,后面的代码不会执行到。

33.自定义异常

必须是自定义类继承Exception,继承的原因是:异常体系中有一个特点,因为异常类和异常对象都被抛出,具有可抛性,这个可抛性是Throwable这个体系中特有的特点。

(2)如果自定义异常时,发现打印的结果中只有异常的名称,没有异常的信息,因为自定义异常并未定义信息。

(3)如果定义异常信息?

因为父类中已经把异常信息都操作了,所以子类只要在构造时,将异常信息传递给父类,通过super语句,那么就可以直接通过getMesaage方法获取自定义异常信息。

(4)通过throw关键字手动抛出一个自定义异常对象,当在函数内部出现了throw抛出异常信息,那么就必须要给对应的处理方式,要么在内部try/catch处理,要么在函数上声明让调用者处理。

34.throw和throws的区别:throws使用在函数上,throw使用在函数内,throws后面跟的是异常类,可以跟多个用逗号隔开,throw后跟的是异常对象。

35.Exception中有一个特殊的子类异常,RunnableException运行时异常,如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过,如果在函数上声明了该异常,调用者也可以不用出来,编译一样可以通过,之所以不用声明是因为不需要让调用者处理,当该异常发生时,希望程序停止,运行时出现了无法继续的运算情况,希望停止程序后。

(2)自定义异常时,如果该异常发生无法在继续进行运算,就让自定义异常继承RunnableException

(3)对于异常情况分两种:编译时被检测的异常,运行异常(RunnableException以及其子类的异常)

不能再throw后面写语句,因为其执行不到,而且还编译失败

35. catch用于处理异常,如果没有catch就代表异常没有被处理,如果该异常是编译时异常,那么必须声明

(2)异常在子父类覆盖情况。

子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类异常或该异常的子类。

如果父 类或者接口中的方法没有抛出异常,则子类在覆盖方法时,也不可以抛出异常,如果子类方法发生异常,就必须要进行try处理,绝对不能抛出。

36.异常的总结

异常的好处:将问题进行封装,将正常流程代码和问题处理代码相互分离,方便于阅读。

异常处理的原则:

1.处理方式有两种:try或throws

2.调用到抛出异常的功能时,抛出几个,就处理几个,一个try对应多个catch。

3.多个catch时,父类的catch放到最后面

37.进程

(1)是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径或者叫一个控制单元

(2)线程:就是进程中一个独立的控制单元,线程在控制着进程的执行,一个进程中至少有一个线程。

 

38.如何自定义一个线程

(1)继承Thread类

步骤:1)定义类继承Thread,重写其中的run方法

  2).调用线程的start方法,该方法有两个作用:启动线程,调用run方法。

发现运行结果每一次都不同,因为多个线程都在获取CPU执行权,CPU执行到谁,谁就运行,在某一个时刻只能有一个重写运行(多核除外),这就是多线程的一个随机性的特点。

(2)实现Runnable类。

步骤:1)定义类实现Runnable接口

  2)覆盖Runnable接口中的run方法,将线程要运行的代码放在该run方法.

  3)通过Thread类建立线程对象.

  4)将Runnable接口的子类对象作用实际参数传递给Thread类的构造函数.为什么要将Runnable接口的子类对象传递给Thread的构造函数.因为自定义的run方法所属对象是runnable接口的子类对象,所以要让线程去调用指定对象的run方法,就必须明确该run方法所属对象

  5)调用Thread类的start方法开启线程并调用Runnable接口的子类的run方法.

39.多线程的运行出现了安全问题,问题原因:多条语句在操作同一个共享数据的时候,一个线程之操作了一部分,而另一个线程又要来操作共享数据,就会导致数据错误情况.

解决办法:对多条操作共享数据的语句,只能让一个线程执行完了,另外一个线程才可以进行操作.

(2)java对于多线程情况提供了解决办法:同步代码块或同步函数.synchronized(对象){需要被同步的代码}。记住:哪些代码操作共享数据,哪些代码就需要被同步。对象如同锁,持有锁的线程可以在同步中执行,没有锁的线程即时有cpu的执行权也不能操作。

(3)同步的前提:1)必须要有两个或两个以上的线程

  2)必须是多线程使用同一把锁。 必须要保证只有一个线程在运行。

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

弊端:多线程需要判断锁,比较消耗资源,和时间。

 39.为什么要覆盖run方法呢,Thread类用于描述线程,该类就定义了一个功能,由于存储线程要运行的代码,该存储功能就是run方法,也就说thread类中的run方法用于存储线程要运行的代码。

Demo d=new Demo()(其中Demo继承了thread类)这表示创建好一个线程

d.start、、开启线程并执行该线程的run方法。而d.run只是函数调用,线程并没有创建.

40.如何查找线程安全问题

(1)明确哪些代码是多线程运行代码

(2)明确共享数据。

(3)明确多线程运行代码中哪些语句是操作共享数据。

40.同步函数用的是哪一个锁。函数需要被对象调用,那么函数都有一个所属对象的引用this,所以同步函数使用的锁是this(非静态)

如果同步函数被静态修饰后,使用的锁是所对应的字节马文件。因为静态方法中不可以定义this,静态进内存的时候,还没有本类的对象,但一定有所对应的字节马文件:类名.class。

41.单利设计模式中懒汉式的多线程问题

class Single {private static Single s=null; private Single(){} public static Single getInstace(){if (s==null) synchronized(Single.class) if(s==null) s=new Single()} return s;}

懒汉式和饿汉式的区别:懒汉式是实力的延迟加载,懒汉式延迟加载有多线程访问时出现安全问题,那么该如何解决呢?可以加同步来解决,用同步代码块和同步函数都可以,所使用的锁是该类对应的字节马文件。

42.停止线程

如何停止线程,只有让run方法结束.开启多线程运行,通常都有循环结构,只要控制住循环就可以让run方法结束.

守护线程/后台线程。当正在运行的线程和别的线程的区别在于,结束时,当前台线程结束时,后台线程就立刻结束。

join,当A线程执行到了B线程的join方法时,A就会等待B线程都执行完了,A才会执行,join用来临时加入线程执行(有点像函数的调用)

 

43.字符串

字符串本身就是一个对象,如:String s="abc" s是一个类类型变量,"abc"是一个对象,字符串最大的特点就是:一旦被初始化就不可以改变。

String s1 =new String("abc") s 和s1的区别是:s在内存中有一个对象,s1在内存中有两个对象,在进行字符串比较的时候,要用equals方法,该方法是比较字符串是否相同。

44.字符串和字节数组在转换过程中是可以指定编码表的,stringBuffer是字符串缓冲区,是一个容器,而且长度可变,可以直接操作多个数据类型,最终通过tostring方法变成字符串。

stringBuffer sb=new StringBuffer();StringBuffer sb1=sb.append("123"),那么sb和sb1内容是一样的都是123字符串。

StringBuffer是线程安全的,StringBuilder是线程不不同步的,StringBulider的执行速度大于StringBuffer,建议使用StringBuilder

 

45.集合框架

为什么会出现那么多的框架容器呢?因为每一个容器的数据结构不一样,集合中存储的都是对象的引用(地址)

List集合:有序的,元素可以重复,因为底层用的是数组的数据结构,有索引的脚标。

set集合是无序的,元素不可以重复,因为没有脚标,list集合可以使用。

list集合可以使用for循环遍历,也可以使用迭代器遍历,(因为有角标,所以可以使用for循环进行遍历)。

46.list集合下面常见的子集合有

(1)ArrayList:底层使用的是数组的数据结构,特点查询速度快,但是增加删除慢,线程不同步。

(2)Linkedlist:底层使用的是链表的数据结构,特点,增加删除快,查询慢。

(3)Vector:底层是数组数据结构,线程同步,已经被ArrayList替代了。

 

47.枚举就是Vector特有的取出方式Enumeration,发现枚举和迭代器很相似。

48.list集合判断元素是否相同,依据的是元素的equal方法,ArrayList集合中,LinkedList集合中的contain,remove,底层使用的都是equal方法。

set集合是无序的,即存入和取出的顺序不一致,元素不可以重复,而HashSet底层使用的是哈希值,而哈希表是先逼急哈希值,如相等,再逼急值,如都一样则不存储否则存储。

set集合的取出方式,只有用迭代器。

 

49.hashSet集合是如何保证元素的唯一性?是通过元素的两个方法进行的,hashcode和equals方法,如果hashcode不相同,那么就没有必要比较equal方法,这两个元素是不同的,如hashcode相同,那么再会比较equal方法,如equal方法,那么就代表这两个元素是相同的,否则不同。

在开发时,一般会覆盖hashcode和equal方法,ArrayList进行包含,删除,依赖的是equal方法,而Hashset进行包含,删除等操作的时候,依赖的是hashcode和equal方法。是线程不同步的。

50.排序时,当主要条件相同的时,一定要判断一下次要条件,

(1)TreeSet可以对set集合中的元素进行排序。

(2)TreeSet底层用的是二叉树的数据结构。

(3)保证元素唯一性的依据compareTo方法return 0

treeset排序的第一种方式,让元素自身具备比较性,元素需要实现Compareable接口,覆盖compareto方法,这种方式也成为元素的自然排序也叫做默认排序。

treeset的第二种排序方式,当元素自身不具备比较性时,或者具备的比较性不是所想要的,那么就让集合本身具备比较性。

51.泛型 静态方法不可以访问类上定义的泛型,如果静态方法操作的数据不确定时候,可以将泛型定义在方法上。

(2)?是通配符,当对象类型不确定的时候,可以使用通配符表示。

? extends E,可以接受E类型或者E的子类型,上限。

? super E,可以接受E类型或者E的付类型,下限。

52.Map

hashtable底层是哈希表数据结构,不可以存入null建和null值,该集合是线程同步的。

hashmap底层使用的是hash表的数据结构,允许null建和null值,是线程不同步的,效率高

treemap,底层使用的是二叉树的数据结构,线程不同步,用于给map集合中的建进行排序,map和set很像,set底层使用的就map。

 

53.IO

IO按照操作数据分为字节流和字符流,字符流里面包含的有编码表,字节流的抽象基类:InputStream,OutputStream,字符流的抽象基类:Reader,Writer。

(2)IO中后缀名是父类名,前缀名是该流对象的功能,调用write方法是将字符串写入到流中(也就是内存中)还没有真正写入到指定的磁盘中。

(3)关闭流close方法(这个是字符流操作的),在关闭之前会刷新一次内部的缓冲中的数据,将数据刷新到指定的目的地。而flush也可以将内存中的数据刷新到目的地,他和close方法区别,flush刷新后,流还可以继续使用,而close方法刷新之后,流将不会再使用,其实close方法是先调用flush方法。

54.文件的数据续写在构造函数时候=传递一个true参数,代表不覆盖已有的文件,并在已有的文件的末尾进行数据的append操作。

(2)文本文件的读取方式,定义一个字符数组,用于存储读到字符,该read返回的是读到的字符个数

(3)缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须要先有流对象,该缓冲区提供了一个跨平台的换行符newLine,记住在使用缓冲区的时,一定要flush一下。

55.字符读取缓冲区:该缓冲区还提供了一个一次读一行的方法,readLine,方法便于对文本数据的获取,当返回null时,表示读到文件的末尾。。

readline方法返回的时,只返回回车符之前的数据内容,并不返回回车符,如果需要换行还需要用newLine。

readLine的原理,无论是读一行,其实最终还是一个一个的获取的,最终还是调用read方法

56.装饰设计模式,对已有的对象进行功能的增强,可以将已有的类对象作为参数进行传递,基于已有的功能并提供加强功能,装饰类通常通过构造函数接受被装饰的对象,并基于被装饰的对象功能,提供更强的功能,如FileWirter的装饰类BuffferedFileWriter。

56.字符流底层走的是字节流。字符流底层是将字节流进行缓冲的,所以在使用的时候要刷新,而直接使用字节流的话,就不需要刷新。

转换流:InputStreamReader是字节流通向字符流的桥梁。

OutputStreamWriter是字符流通向字节流的桥梁。

转换流的最大的好处就是可以指定字符编码集,所以通常涉及到编码表的时候会使用到转换流

57.IO中的read方法是一个阻塞的方法,Io不可以对文件的属性进行操作,file类可以对文件的属性进行操作

58.properties是hashtable的子类,也就是说它具体map的集合的特点,而且它存储的数据都是字符串

(2)properties是集合和IO技术相结合的集合容器

该对象的特点可以用于建值对形式的配置文件,那么在加载数据的时候,需要:建=值。

编码表中gbk2个字节代表一个字符,utf-83个字节代表一个字节。

58.网络编程

javase中的网络编程时在网络层和传输层,而javaweb开发是在会话层,表现层,应用层。底层都在的是网络层,网络层有IP协议,传输层有TCP/UDP层协议,应用层中有http,ftp等协议。

udp将数据及源和目的封装成数据包中,不需要建立连接,每个数据包的大小限制在64K内,无连接,不可靠协议。不需要建立连接,速度快,

tcp,建立连接,形成传输层数据通道,在连接中进行大量数据传输,通过三次握手协议,是可靠的协议,必须建立连接,效率低。

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

常见的udp有:聊天软件,视频会议。

常见的TCP有,下载功能。

60.通过udp传输方式,过程

(1)建立udp的socket服务(创建Datagramsocket对象即可)

(2)提供数据,并将数据封装成数据包(创建DatagramPacket)

(3)通过socket服务的发送功能,发送出去(send方法)

(4)关闭资源

udp接收数据

(1)定义udp的socket服务,通常会坚挺一个端口,其实就是给这个接收网络应用程序一个数字标示,方便于明确哪些数据过来(通过DatagramSocket构造函数来指定端口)

(2)定义一个数据包,因为要存储接收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同的数据信息(通过创建一个Datagrampacket)

(3)通过socket服务的receive方法将接收到的数据存入到已经定义好的数据包中

(4)通过数据包的特有对象的功能,将这些数据取出如,getData,getPart等

(5)关闭资源

61.TCP分为客户端和服务端,其中客户端对应的是socket,服务端对应的是serverSocket(下面是客户端和服务端互访的步骤)

(1)客户端

1.创建socket服务,并指定要连接的主机和端口(通过创建socket对象完成)

2.为了发送数据,应该获取socket流中的数据输出流(通过getOutputStream)再调用write方法输出,将数据写到流中

3.服务端通过对应的流的输入流(InputStream)方法获取所得到的数据后,再通过对应流的输出流将回应输出到客户端,客户端在通过输入流来获取数据

4.关闭客户端(close方法)

(2)服务端

1.建立服务端的socket服务,通过serverSocket来建立,并监听一个端口,获取链接过来的客户端对象,通过serverSocket的accept方法来获取数据,这个方法是阻塞方法

2.客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到客户端对象的读取流来读取发过来的数据(通过getInputStream)

再通过OutputStream的输出流对象给客户端进行回应

3.关闭流(对于服务端来说这是可选择的)

 

62.当多个客户端连接服务端的时候,为什么不发生冲突,服务器怎样操作的呢?

因为服务端没有流对象,客户端连接到服务端时,服务端就会拿到对应的客户端对象和他对应的数据进行操作,这样就可以保证服务器所操作的是对应请求的客户端

tcp编程中必须先启动服务端

63.服务端中应该写多线程技术,因为当多个客户端并发送请求时,服务端需要同时操作他们,这时就需要将服务端中对应客户端的代码放入到run方法中,urlConnection走的是应用层,socket走的是传输层

64.线程中的yeld方法,让出cpu给其他线程执行的机会,在某一时刻一定是被线程进行的。

wait和sleep方法的区别

wait是object中的方法,sleep是类中的方法

wait在等待时候会释放执行权,而sleep在等待的时候还一直拥有执行权,直到时间到了醒了

转载于:https://www.cnblogs.com/wangtao-bgs/p/6372027.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值