java基础

来源:互联网 发布:python3写网络爬虫 编辑:程序博客网 时间:2024/04/30 08:39

java语言的特点

  • 简单,稳定,面向对象,跨平台,多线程,多态性,安全

Liunx操作系统和windows操作系统的区别,常用命令有哪些

  • Liunx操作系统是开源,免费的操作系统,主要用于服务器端操作系统,java主要是服务器端开发,所以最终部署环境一般都是Liunx,
  • Liunx与Windows目录结构的区别:
    • 文件系统不同: Linux目录,windows盘符
    • 安全级别不同: Liunx高 windows低
    • 外部设别不同: Liunx挂载点 Windows盘符
  • Liunx常用命令
    • pwd :显示当前工作目录
    • ls :查看当前工作目录的内容
    • cd :改变当前工作目录 .:当前目录..: 上一级目录

java运行过程

java遵循先编译后运行的过程,首先通过javac命令将java源文件编译为java字节码.class文件,之后通过java命令去启动jvm,由jvm来加载.class文件。

JDK,JRE,JVM的关系

  • JDK:Java开发工具包,包含编写Java程序所必须的编译、运行等开发工具以及JRE。
  • JRE:Java运行环境,提供了运行Java应用程序所必须的软件环境,包含有Java虚拟机(JVM)和丰富的系统类库。
  • JVM:Java虚拟机,提供了字节码文件(.class)的运行环境支持.

内存管理

  • JVM会将申请到的内存从逻辑上划分为三个区域:堆、栈、方法区。这三个区域分别用于存储不同的数据。
    堆:用于存储使用new关键字所创建的对象以及对象的属性成员变量。
    栈:用于存储程序运行时在方法中声明的所有的局部变量。
    方法区:用于存放类的各种信息(包括方法)都在方法区存储。

static关键字可以修饰什么

  • static修饰的变量是静态变量,修饰的方法是静态方法,可以和final共同修饰常量,也还可以单独作为静态块存在.
    static修饰的属性,方法都是独一份,可以被多个对象共用,因为与对象无关,属于类,所以直接用类名调用.

静态变量和实例变量的区别

  • 在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
    在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

重写的两同两小一大规则

  • 重写要遵循”两同两小一大”原则:
    • 两同:1)方法名相同 2)参数列表相同
    • 两小: 1)子类方法的返回值类型小于或等于父类的
      1.1)void时必须相等
      1.2)基本类型时必须相等
      1.3)引用类型时小于或相等:父类大,子类小
      2)子类抛出的异常小于或等于父类的
    • 一大:子类方法的访问权限大于或等于父类的

构造函数

注意: 构造子类之前必须先构造父类,子类构造方法中若没有调用父类的构造方法,则默认super()调父类的无参构造,若子类构造方法中调用了父类的构造方法,则不再默认提供super()调父类构造必须位于子类构造方法的第一句,默认存在.
且不能与this()同时使用,因为this()和super()都要求存在构造方法的第一行,会产生竞争,编译错误.

java中实现多态的机制是什么

  • 靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

abstract class抽象类和interface接口有什么区别

  • 含有abstract修饰符的class即为抽象类,抽象类不能创建的实例对象。含有抽象方法的类必须定义为abstract class.
  • 接口(interface)可以说成是一种特殊的抽象类,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
  • 下面比较一下两者的语法区别:
    • 抽象类可以有构造方法,接口中不能有构造方法。
    • 抽象类中可以有普通成员变量,接口中没有普通成员变量
    • 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
    • 抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse不报错,但也不行,默认类型子类不能继承),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型.
    • 抽象类中可以包含静态方法,接口中不能包含静态方法
    • 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
    • 一个类可以实现多个接口,但只能继承一个抽象类,接口不可以实现接口,但可以继承接口并且可以继承多个接口,用逗号隔开.

内部类是否可以引用它的包含类的成员有,没有什么限制

  • 完全可以。如果不是静态内部类,那没有什么限制!
    如果是静态内部类,那在这种情况下不可以访问外部类的普通成员变量,而只能访问外部类中的静态成员。

什么是匿名内部类

  • 若想创建一个类(子类)的对象,并且对象只被创建一个,此时该类不必命名,称 之为匿名内部类
  • 匿名内部类中访问外部的变量,该变量必须是final的.

String这个类常用的处理字符串的方法

indexOf:检索指定字符在字符串中第一次出现的位置.
substring:用来截取当前字符串,含头不含尾
trim:去除字符串两边的空白
charAt:给定一个下标,获取该下标对应的字符
startsWith:是否以给定字符串开始.
endsWith:是否以给定字符串结尾
toUpperCase:将当前字符串引文部分全部转换为大写
toLowerCase:将当前字符串英文部分全部转换为小写
valueOf:将基本类型的值转换为字符串

StringBuilder这个类常用的处理字符串的方法

append(String str):追加字符串;
insert (int dstOffset,String s):插入字符串;
delete(int start,int end):删除字符串;
replace(int start,int end,String str): 替换字符串;
reverse():字符串反转.

包装类的自动拆装箱

  • 将基本类型转换为包装类时,我们可以调用包装类的一个静态方法valueOf():
    Integer i = Integer.valueOf(1);
    Double d = Double.valueOf(1.1):
    将包装类转换为基本类型时,我们可以使用包装类的方法xxxValue()方法
    Integer i = new Integer(1);
    int n = i.intValue();
    Double d = new Double(1.1);
    double dn = d.doubleValue();
  • 因为i1和i2使用new关键字new了两次,在堆内存中创建了2个对象,所以==比较为false,内容相同equals比较为true
    Integer i3=Integer.valueOf(i);
    Integer i4=Integer.valueOf(i);
    System.out.println(i3==i4);
    System.out.println(i3.equals(i4));
    输出结果为false true
    在包装类的内存中有一块区域,缓存着Integer的byte范围内的值(-128~127),如果未超出此范围,则直接在该缓存区取值,并不会在堆中创建新对象,如果超出此范围则会在堆内存中创建新对象.
    如上代码i=128超出了取值范围,则在i3和i4创建了两个对象,所以双等号比较为false,内容相同equals比较为true
    注意:如果i=127,通过new关键字创建的对象也是两个对象,通过valueOf()创建的对象为同一个对象.
  • List是可重复集合,Set是不可重复集合,这两个接口都实现了Collection父接口.
    Map未继承Collection,而是独立的接口, Map是一种把键对象和值对象进行映射的集
    合,它的每一个元素都包含了一对键对象和值对象, Map中存储的数据是没有顺序的,
    其key是不能重复的,它的值是可以有重复的。
    List的实现类有ArrayList, Vector和LinkedList.
    ArrayList和Vector内部是线性动态数组结构,在查询效率上会高很多,Vector是线程安全的,相比ArrayList线程不安全的,性能会稍慢一些.
    LinkedList:是双向链表的数据结构存储数据,在做查询时会按照序号索引数据进行前向或后向遍历,查询效率偏低,但插入数据时只需要记录本项的前后项即可,所以插入速度较快。
    Set的实现类有HashSet和TreeSet;
    HashSet: 内部是由哈希表(实际上是一个 HashMap 实例)支持的。它不保证 set元素的迭代顺序.
    TreeSet: TreeSet使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序.
    Map接口有三个实现类:Hashtable,HashMap,TreeMap,LinkedHashMap
    Hashtable: 内部存储的键值对是无序的是按照哈希算法进行排序,与HashMap最大的区别就是线程安全.键或者值不能为null,为null就会抛出空指针异常
    HashMap: 内部存储的键值对是无序的是按照哈希算法进行排序,与Hashtable最大的区别就是非线程安全的,键或值可以为null
    TreeMap: 基于红黑树(red-black tree)数据结构实现, 按 key 排序,默认的排序方式是升序.
    LinkedHashMap:有序的Map集合实现类,相当于一个栈,先put进去的最后出来,先进后出.

ArrayList和Vector的区别

  • ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差。而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,索引就变慢了,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
  • 这两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,我们以后可以按位置索引号取出某个元素,HashSet之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素。
    • 同步性:
      Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的.
    • 数据增长:
      ArrayList与Vector都有一个初始的容量大小,Vector默认增长为原来两倍,而ArrayList的增长策略是增长为原来的1.5倍。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。
      总结:即Vector增长原来的一倍,ArrayList增加原来的0.5倍。

怎么实现集合中引用类型元素的自定义排序

当一个类实了Comparable接口后,接口要求必须重写方法comparaTo,该方法的作用
是定义当前对应于参数给定对象比较大小规则
方法要求返回一个整数,该整数不关注具体值,只关注取值范围,即:
当返回值>0当前对象大于参数对象
当返回值<0当前对象小于参数对象
当返回值=0两个对象相等
然后在使用时直接调用Collections.sort(list);传入要比较的集合就会按照自己定义的比 较规则进行比较.
注: 该方法在排序自定义元素时,对我们的程序有侵入性
侵入性:当我们使用一个功能时,该功能要求我们为其修改的代码越多,侵入性越强高侵入性不利于程序扩展,应尽量避免, 侵入性的弊端是一旦该功能不再需要时,之前修改的代码都不具意义,增加后期维护代码成本

List集合有哪些常用方法

List接口继承自Collection接口, 是可重复集,并且有序. 提供了一系列支持使用下标操作元素的方法:
E get(index): 获取指定下标处的元素
E set(int index,E e):将给定的元素设置到指定位置处,返回值原位置元素
E remove(int index):删除并返回指定下标处的元素,返回为原位置的元素
boolean remove(Object o): 删除集合中与给定元素equals比较为true的元素
boolean add(E e):向集合内添加一个元素
void add(int index,E e): 在指定位置插入规定元素
void clear():清空集合
List subList(int start,int end): 截取当前集合中指定范围的子集.
注: 对子集的操作就是对原集合中对应元素的操作

Map集合有哪些常用方法

Value put(Key k,Value v): 将给定的Key - Value 对存入到Map中返回值为被替换的value.注:Map不允许有重复的Key,若存入的key已经存在与Map中,则是替换value操作,返回值就是被替换的value,若存入的key在Map中不存在,则返回值为Null
Value get(Key k): 根据给定的key获取对应的value.
Value remove(Key k): 根据给定的key删除这组键值对,返回值是该键值对的value若没有,则返回null.

遍历Map有几种方式

一共三种方式:
1) Set keySet():遍历所有的key, 将当前Map中所有的key存入到一个Set集合后返回

重写equals方法的规则

1).如果传过来的obj是null那么就返回false
2).如果obj==this,传过来的obj和当前对象时同一个对象,返回true
3).如果obj 和当前对象是相同类型,则返回当前对象和obj的属性的比较,否则返回false
public boolean equals(Object obj){
if(obj==null){
return false;}
if(obj==this){
return true;}
if(obj instanceof Point){
Point p=(Point)obj;
return this.x==p.x&&this.y==p.y;}
return false;}

为什么要重写hashcode()和equals()

  • hashcode方法.并且两个方法应满足:
    1:一致性,即:当两个对象equals比较为true,那么hashcode值应当相等.反之亦然.
    因为当两个对象hashcode值相等,但是equals比较为false,那么在HashMap中
    会产生链表,影响查询性能.
    2:成对重写,即重写equals就应当重写hashcode.

File是对文件做哪些操作,有哪些常用方法

File只是访问文件属性,比如:名字,可读,可写,修改时间,字节大小,是否可运行权等,但是不能访问文件内部的内容.另外还可以通过File创建文件和目录.
File file=new File();可以传入文件路径及文件名来访问该文件,默认是当前项目根目录.
访问文件属性常用方法:
file.getName():获取文件名
file.length():获取文件字节长度
file.canRead():是否可读
file.canWrite():是否可写
file.canExecute():是否可运行权
file.lastModified():最后修改时间
file.isHidden():是否被隐藏
创建文件常用方法:
file.exists():判断文件是否存在:true表示存在
file.createNewFile():创建新文件,依据file中的路径和文件名进行创建
file.delete():删除文件
创建目录常用方法:
File dir=new File();可以传入一个文件路径及目录名,不加文件类型后缀就是目录
dir.exists():判断目录是否存在:true表示存在
dir.mkdir():创建目录,注:mkdir也是Linucs的创建目录命令
dir.getName():获取目录名
dir.delete():删除目录
dir.mkdirs();创建嵌套多级目录:目录名为最内层的目录名
注意:删除多级目录时:
由于delete()删除目录时需要保证目录内部使空的才可以,如果要删除多级目录时
需要先将内部的文件或目录删除
dir.listFiles():获取一个目录下的所有子项
dir.isDirectory():判断当前File表示的是否为目录
dir.isFile():判断当前File表示的是否为文件
例如:删除多级目录先判断目录内部是文件还是目录,如果是目录则可以获取其内部
所以子项,是文件就直接删除

IO流是做什么的?流的分类?常用的流有哪些

IO流指的是输入输出流,用来处理设备上的数据。这里的设备指硬盘,内存,键盘录入,网络传输等。
1)根据数据的流向来分:
输出流:是用来写数据的,是由程序(内存)—>外界设备
输入流:是用来读数据的,是由外界设备—>程序(内存)
2)根据流数据的格式来分:
字节流:处理声音或者图片等二进制的数据的流,比如InputStream
字符流:处理文本数据(如txt文件)的流,比如InputStreamReader
3)根据流数据的包装过程来分:
节点流:又称为低级流,特点是:数据源明确,真实负责读写数据的流
处理流:又称为高级流,特点是:不能单独存在(没意义),用来处理其他流,所有高级流都封装了某些特定功能的读写操作,目的是简化我们的读写操作具体的流:
1)字节流:
InputStream与OutputStream
InputStream是所有字节输入流的父类,其定义了基础的读取方法
OutputStream是所有字节输出流的父类,其定义了基础的写出方法
包含:
文件流:FileOutputStream是文件的字节输出流,我们使用该流可以以字节为单位将
数据写入文件(默认覆盖模式,第二个参数设施为true可改变为追加模式)。
FileInputStream是文件的字节输入流,我们使用该流可以以字节为单位读取
文件内容。
缓冲流:BufferedOutputStream缓冲字节输出流,需使用flush方法将缓存的字节写
出或者在关闭流时一次性写出.
BufferedInputStream是缓冲字节输入流.
对象流:ObjectOutputStream是用来对对象进行序列化的输出流。
ObjectInputStream是用来对对象进行反序列化的输入流。
2)字符流:Reader和Writer
Reader是所有字符输入流的父类。
Writer是所有字符输出流的父类。
字符流是以字符(char)为单位读写数据的。一次处理一个unicode。字符流都是高级
流,其底层都是依靠字节流进行读写数据的。
包含:
转换流:InputStreamReader:字符输入流,使用该流可以设置字符集
OutputStreamWriter:字符输出流,使用该流可以设置字符集
字符缓冲流:
PrintWriter具有自动行刷新的缓冲该字符输出流,需第二个参数设置为true
BufferedReader是缓冲字符输入流
注: PrintWriter写出字符串时我们通常不使用Writer提供的write()相关方法,而是使用重载的print和println方法.
BufferedReader读取字符串时可以使用readLine()连续读取一行字符串,直到读取到换行符为止,返回的字符串中不包含该换行符,未读到返回null

什么是序列化和反序列化?在IO流中哪种流是处理序列化和反序列化的

  • 在java中,可以将任何的对象都转换成一组字节存储到硬盘等载体上,这个过程称为序列化,反序列化就是把一组字节读取出来转换成原对象的过程.
    在序列化和反序列化的过程中需要让对象的实体类实现序列化接口Serializable,生成序列化ID,通过该ID进行序列化和反序列化,并且在转换过程中需要保证ID的一致性.
    在IO流中,负责处理序列化和反序列化的两个流分别是:字节对象流中的:
    对象输出流:ObjectOutputStream:序列化
    对象输入流:ObjectInputStream:反序列化

try、catch、finally语句块的执行顺序(无return情况下)

  • 1)当try没有捕获到异常时:
    try语句块中的语句逐一被执行,程序将跳过catch语句块执行finally语句块和其后的语句;
    2)当try捕获到异常,catch语句块里没有处理此异常的情况:
    当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;
    3)当try捕获到异常,catch语句块里有处理此异常的情况:
    在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;

try、catch、finally语句块的执行顺序(有return返回值的情况)

  • 我们知道finally{}中的语句是一定会执行的,那么这个可能正常脱口而出就是return之前,return之后可能就出了这个方法了,鬼知道跑哪里去了,但更准确的应该是在return中间执行,请看下面程序代码的运行结果:
    public classTest {
    public static void main(String[]args) {
    System.out.println(newTest().test());;
    }
    static int test()
    {
    intx = 1;
    try
    {
    returnx;
    }
    finally
    {
    ++x;
    }
    }

}

———执行结果 ———
1
运行结果是1,为什么呢?主函数调用子函数并得到结果的过程,好比主函数准备一个空罐子,当子函数要返回结果时,先把结果放在罐子里,然后再将程序逻辑返回到主函数。所谓返回,就是子函数说,我不运行了,你主函数继续运行吧,这没什么结果可言,结果是在说这话之前放进罐子里的。

1)try里有return ,catch和finally中无return,未发生异常:
try中return前的语句执行完毕后跳过return语句和catch语句块,先执行finally块中的代码,然后在回到try中执行return语句结束当前方法.
2)try里有return, catch中有return,finally中无return, 发生异常:
try中发生异常的代码之后不再执行,进入catch块中处理异常,但暂时先不执行catch中的return,先进入finally块执行finally块中代码然后再回到catch块中执行return语句结束方法.
3)try里有return,catch中有return,finally中有return,发生异常:
try中发生异常的代码之后不在执行,进入catch块中处理异常,然后执行catch中的return取出返回值将值临时保存在栈中但不是执行return结束方法,然后进入finally块中执行代码最后执行finally中取出返回值覆盖try中的return取出的返回值结束方法.
4)try里有return,cacth中有return,finally中有return,没有发生异常
try中代码包括return都会执行,但是并不会从try中return结束该方法,而是执行try中return取出返回值将值临时保存在栈中,然后会向后继续执行finally块中代码并执行finally中return取出返回值覆盖try中的return取出的返回值结束方法.
可参考如下代码并使用DEBUG方式进行各种情况测试观察结果:
public static void main(String[] args) {
System.out.println(test()); }
public static int test(){
int num = 10;
try{
System.out.println(“try”);
return num += 80;
}catch(Exception e){
System.out.println(“error”);
}finally{
if (num > 20){
System.out.println(“num>20 : ” + num); }
System.out.println(“finally”);
num = 100;
return num; } }
注意:虽然3和4实现在finally中加入return并未报错,但是不建议在finally中加return语句.,会造成两个如下后果:
1) 如果catch块中捕获了异常, 并且在catch块中将该异常throw给上级调用者进行处理, 但finally中return了, 那么catch块中的throw就失效了, 上级方法调用者是捕获不到异常的.
2) finally块中的return语句会覆盖前面的return语句(try块、catch块中的return语句)

throw和throws的区别

throws:是用来声明一个方法可能抛出的所有异常信息,多个异常之间逗号隔开,写在方 法上, 通常不用显示的捕获异常,可由系统自动将所有捕获的异常信息抛给上级调用者.
throw:是指抛出的一个具体的异常类型,写在方法的内部, 需要用户自己捕获相关的异
常,而后在对其进行相关包装,最后在将包装后的异常信息抛出.

子类方法重写父类含有throws异常抛出声明的方法时throws重写规则

假设有一个父类:
public class Aoo {
public void dosome() throws IOException,AWTException{
}}
那么子类继承父类后重写父类方法时:
1) 允许不再抛出任何异常
public void dosome(){}
}
2) 允许抛出部分异常
public void dosome() throws IOException{}
}
3) 允许抛出子类型异常
public void dosome() throws FileNotFoundException{
}
4) 不允许抛出额外异常
public void dosome() throws SQLException{
}
5) 不允许抛出父类型异常
public void dosome() throws Exception{
}

怎么写一个自定义异常

  • 所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception,Error表示应用程序本身无法克服和恢复的一种严重问题,例如,说内存溢出和线程死锁等系统问题。Exception表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常:系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件挂掉,例如,数组脚本越界,空指针异常、类转换异常;
    普通异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。
    java为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须try..catch处理或用throws声明继续抛给上层调用方法处理,所以普通异常也称为checked异常,而系统异常可以处理也可以不处理,所以,编译器不强制用try..catch处理或用throws声明,所以系统异常也称为unchecked异常。
  • 创建一个类继承Exception或者RuntimeException
    继承Exception时自定义异常属于检查型异常,编译器会做检查,会主动提示抛出.
    继承RuntimeException时自定义异常属于运行时异常,编译期不会检查,运行时会抛出相关异常.

Overloaded的方法是否可以改变返回值的类型

  • 如果几个Overloaded的方法的参数列表不一样,它们的返回者类型当然也可以不一样。
  • 如果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载Overload。这是不行的,我们可以用反证法来说明这个问题,假设类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,java就无法确定编程者倒底是想调用哪个方法了,因为它无法通过返回结果类型来判断。
原创粉丝点击