1、java的单一继承使代码更可靠
1、Java是单继承,但是可以实现多个接口。为什么不能实现类的多继承?为了防止多个类中有相同的方法名,这个时候,子类不知道要重写哪一个方法,但是接口可以有多个,因为接口没有方法体,无论重写哪一个,没有区别。
2、定义一个接口使用的关键字为interface
3、this是当前对象的引用,super表示的是当前类的父类对象的引用
4、假设一个 list初始化为{2,9,5,4,8,1}。 在第一轮冒泡排序后,list变成了{2, 5, 4, 8, 1, 9}
1、首先先明白冒泡排序的机制: 依次比较相邻的两个数,将小数放在前面,大数放在后面。 即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。 在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。
5、Java中所有的类都直接或间接继承自Object,无论是否明确的指明,无论其是否是抽象类。
1、Object是基类Java中的所有的类都直接或间接的继承。 2、从一个class派生的必然是另一个class。Object是一个class,如果interface继承自Object,那么interface必然是一个class 3、java中接口跟类是两个并行的概念,所有类都继承Object,但接口是接口,不继承Object. 4、接口是一系列方法声明的开放集合,即所有实现了该接口的类都具备该接口公开的方法,通常为了隐藏实现以及程序的可拓展性用到接口,因为在所有可以使用接口的地方都可以使用它的实现类来替换。
6、A有构造方法A(int a),则在类A的其他构造方法中调用该构造方法和语句格式为 this(x)
1、this的作用其中一个就是在一个构造方法中调用另一个构造方法,格式为this(参数) 2、this.A(x)为调用普通方法的写法 3、super(x)为调用父类方法的写法 4、A(a)这种形式是在new一个类时使用
7、toString和valueOf返回的都是字符串,只有在char类型变成int类型是才返回的是对应的assic编码
public static String toString(char c) { return String.valueOf(c); } public static String valueOf(char c) { char data[] = {c}; return new String(data, true); }
8、哪些具体实现类可以用于存储键,值对,并且方法调用提供了基本的多线程安全支持:
1、java.util.Hashtable: Hashtable是线程安全的哈希表,它是通过synchronized来保证线程安全的; 即,多线程通过同一个“对象的同步锁”来实现并发控制。Hashtable在线程竞争激烈时,效率比较低(此时建议使用ConcurrentHashMap)。当一个线程访问Hashtable的同步方法时,其它线程如果也在访问Hashtable的同步方法时,可能会进入阻塞状态。 2、Collections.synchronizedMap()使用了synchronized同步关键字来保证对Map的操作是线程安全的。 3、ConcurrentHashMap是线程安全的哈希表。在JDK1.7中它是通过“锁分段”来保证线程安全的,本质上也是一个“可重入的互斥锁”(ReentrantLock)。多线程对同一个片段的访问,是互斥的;但是,对于不同片段的访问,却是可以同步进行的。在JDK1.8中是通过使用CAS原子更新、volatile关键字、synchronized可重入锁实现的。
9、final关键字:
1、final修饰的类不能被继承 2、final修饰变量,则等同于常量。 3、final修饰方法中的参数,称为最终参数 4、final修饰类,则类不能被继承 5、final修饰方法,则方法不能被重写。 6、final 不能修饰抽象类 7、final修饰的方法可以被重载 但不能被重写
10、抽象方法只能定义在抽象类中,抽象方法和抽象类必须由abstract修饰,abstract关键字只能描述类和方法,不能描述变量。抽象方法只定义方法声明,不定义方法实现。抽象类不可以被实例化(创建对象),只有通过子类继承抽象类并覆盖抽象类中的所有抽象方法后,该子类才可以被实例化,否则该子类还是一个抽象类。抽象类中有构造函数用于给子类对象进行初始化,同时抽象类中可以含有非抽象方法。abstract关键字不可以与final,private,static关键字共存,因为被final修饰的方法不可以被重写,意味着子类不可以重写该方法,如果abstract和final共同修饰父类中的方法,子类要实现抽象方法(abstract的作用),而final又不让该方法重写,这相互矛盾。如果private和abstract共同修饰父类中的方法,private修饰则该方法不可以被子类访问,但是abstract修饰需要子类去实现,两者产生矛盾。如果static和abstract共同修饰父类中的方法,static表示是静态的方法,随着类的加载而加载,则该方法不需要在子类中去实现,这与abstract关键字矛盾。
11.static用于修饰成员变量和成员函数,想要实现对象中的共性数据的对象共享,可以将这个数据进行静态修饰,被静态修饰的成员可以直接被类名调用,静态随着类的加载而加载,而且优先于对象存在。静态方法只能访问静态成员(静态方法和静态变量),不可以访问非静态成员,这是因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员。静态方法中不能使用this和super关键字,因为this代表本类对象,super代表父类对象,而静态时,有可能没有对象存在,所以this和super无法使用。
12.final关键字可以修饰类,方法,变量(成员变量内,局部变量,静态变量),被final修饰的类是一个最终类,不可以被继承,被final修饰的方法是一个最终方法,不可以被覆盖,但是可以被继承。被final修饰的变量只能是一个常量,只能赋值一次。内部类被定义在类中的局部位置上时,只能访问局部被final修饰的局部变量。
13、对于public修饰符,它具有最大的访问权限,可以访问任何一个在CLASSPATH下的类、接口、异常等。它往往用于对外的情况,也就是对象或类对外的一种接口的形式。 对于protected修饰符,它主要的作用就是用来保护子类的。它的含义在于子类可以用它修饰的成员,其他的不可以,它相当于传递给子类的一种继承的东西。 对于default来说,有点的时候也成为friendly(友员),它是针对本包访问而设计的,任何处于本包下的类、接口、异常等,都可以相互访问,即使是父类没有用protected修饰的成员也可以。 对于private来说,它的访问权限仅限于类的内部,是一种封装的体现,例如,大多数的成员变量都是修饰符为private的,它们不希望被其他任何外部的类访问。
14、接口可以继承接口,而且可以继承多个接口,但是不能实现接口,因为接口中的方法全部是抽象的,无法实现;普通类可以实现接口,并且可以实现多个接口,但是只能继承一个类,这个类可以是抽象类也可以是普通类,如果继承抽象类,必须实现抽象类中的所有抽象方法,否则这个普通类必须设置为抽象类;
拓展: 1、抽象类可以实现接口,可以继承具体类,可以继承抽象类,也可以继承有构造器的实体类。抽象类中可以有静态main方法;抽象类里可以没有抽象方法,没有抽象方法的抽象类就是不想让别人实例化它;另外,抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。在继承了抽象类的子类中通过super(参数列表)调用抽象类中的构造方法,可以用于实例化抽象类的字段。 抽象类与接口的区别: 1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象; 2、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现(java8中 接口可以有实现方法 使用default修饰); 3、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量; 4、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个类实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类; 5、抽象方法要被实现,所以不能是静态static的,也不能是私有private的,也不能被final修饰(试想一下,静态方法可以被类名直接调用,而类名直接调用一个没有实现的抽象方法没有意义)
15、常见的异常:
1、java.lang.NullPoninterException(空指针异常) 2、java.lang.NumberFormatException(数字格式异常) 3、java.lang.RuntimeException(运行时异常) 4、java.lang.ArrayindexOutOfBoundsException(数组下标越界异常)
16、线程: 1、线程通过使用synchronized关键字可获得对象的互斥锁定。
2、采用synchronized修饰符实现的同步机制叫做互斥锁机制,它所获得的锁叫做互斥锁。每个对象都有一个monitor(锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个锁是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线程,因此叫做互斥锁。 3、对于线程而言,start是让线程从new变成runnable。run方法才是执行体的入口。但是在Thread中,run方法是个空方法,没有具体实现。Bground继承了Thread,但是没有重写run方法,那么调用run方法肯定是无输出。
17、我们在为Integer赋值的时候,java编译器会将其翻译成调用valueOf()方法。比如Integer i=127翻译为Integer i=Integer.valueOf(127)
public static Integer valueOf(int i) { //high为127 if(i >= -128 && i <= IntegerCache.high) return IntegerCache.***[i + 128]; else return new Integer(i); }
这样可以看出对于-128到127之间的数,Java会对其进行缓存。而超出这个范围则新建一个对象。 所以现在回到这道问题i1和i2为128,超出范围,所以都需要新建对象,对象比较为false; i5和i6为100,在范围之内,在执行Integer i5=100时,就会直接缓存到内存中,但执行执行Integer i6=100时,就直接从缓存里取,而不需要新建对象,所以为true。
18、volatile:
1、synchronized保证三大性,原子性,有序性,可见性,volatile保证有序性,可见性,不能保证原子性 拓展: volatile到底做了什么? 1、禁止了指令重排; 2、保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量值,这个新值对其他线程是立即可见的; 3、不保证原子性(线程不安全) synchronized与volatile关键字比较: 1、volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。synchronized关键字在JavaSE1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升,实际开发中使用 synchronized 关键字的场景还是更多一些。 2、多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞。 3、volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。 4、volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程之间访问资源的同步性。
20、客户端与服务端之间的连接:
TCP客户端: 1、建立连接套接字,设置Ip和端口监听,socket(); 2、建立连接 connect; 3、write() 获取网络流对象 发送数据 4、read()获取网络流对象 接收数据; 5、关闭套接字 TCP服务器端: 1、建立端口监听 socket() 2、绑定指定端口 bind() 3、listen 进行端口监听 4、accept() 阻塞式 直到有客户端访问 5、read()获取客户端发送数据 6、write()发送返回数据 7、close关闭端口监听 概述来说: 首先是服务器初始化Socket,然后是与端口进行绑定(blind()),端口创建ServerSocket进行监听(listen()),然后调用阻塞(accept()),等待客户端连接。与客户端发生连接后,会进行相关的读写操作(read(),write()),最后调用close()关闭连接
21、java中标识符的组成:由52个字母A-Z ,a-z ,数字0-9 ,下划线_ , 美元符$ 组成, 但是不能用数字开头! 3、与InputStream流相对应的Java系统的“标准输入对象”
1、System.in (标准输入) 2、System.out (标准输出 ) 3、System.err (输出错误) 4、System.exit()(结束程序)
public class Demo{ public static void main(String args[]){ int num = 10; System.out.println(test(num)); } public static int test(int b){ try { b += 10; return b; } catch(RuntimeException e) { } catch(Exception e2) { } finally { b += 10; return b; } } }
24、ArrayList:增删慢,查询快。 由于是数据组实现,需要连续的内存空间,如果删除数组中间的值,为了保证下标的有效性,需要将后面的数据往前移,所以删除慢。 当插入A对象到B对象的前面时,需要将B对象和B对象之后的所有对象后移一位,再插入A对象。所以插入慢。 数组的大小是固定的,如果数组满了,需要重新分配空间,new一个新数组并copy旧数据之后再增加新数据,所以增加慢。 因为是连续内存空间,可以通过下标查询数据,所以查询快。 LInkedList:增删快,查询慢。 由于是链表实现,当前节点的next指向下一个节点,prev指向上一个节点,不需要连续的内存空间,所以增删快。 因为不是连续内存空间,所以不能使用下标查询,只能通过next遍历,所以查询慢。
25、Java致力于检查程序在编译和运行时的错误。 Java虚拟机实现了跨平台接口 类型检查帮助检查出许多开发早期出现的错误。 Java自己操纵内存减少了内存出错的可能性。 Java还实现了真数组,避免了覆盖数据的可能。 注意,是避免数据覆盖的可能,而不是数据覆盖类型
注: 数组元素在内存中是一个接着一个线性存放的,通过第一个元素就能访问随后的元素,避免了数据覆盖的可能性,和数据类型覆盖并没有关系。 8、什么情况下要使用抽象类? 1、一个类中有抽象方法则必须申明为抽象类。 2、抽象类中的抽象方法必须由其子类实现,若子类不能实现则子类也必须定义为抽象类。 3、 一个类实现一个接口就必须实现其中所有的抽象方法,若该实现类不能实现接口中的所有方法则实现类定义为抽象类 抽象类特点:用abstract修饰,抽象类中可以没有抽象方法,但抽象方法肯定在抽象类中,且抽象方法定义时不能有方法体; 抽象类不可以实例化只能通过继承在子类中实现其所有的抽象方法;抽象类如果不被继承就没有任何意义; 抽象类为子类定义了一个公共类型,封装了子类中的重复内容。
26、ArrayList、LinkedList、HashMap:
1、ArrayList插入和现有项的删除开销很大,除非在末端 2、LinkedList插入和删除开销很小 3、ArrayList和LinkedList都是实现了List接口 HashMap可以用null值和空字符串作为K,不过只能有一个
27、Java中的共享资源和私有资源
共享资源 1、 堆 由于堆是在进程空间中开辟出来的,所以它是理所当然地被共享的;因此new出来的都是共享的(16位平台上分全局堆和局部堆,局部堆是独享的) 2、全局变量 它是与具体某一函数无关的,所以也与特定线程无关;因此也是共享的 3、静态变量 虽然对于局部变量来说,它在代码中是“放”在某一函数中的,但是其存放位置和全局变量一样,存于堆中开辟的.bss和.data段,是共享的 4、文件等公用资源 这个是共享的,使用这些公共资源的线程必须同步。Win32 提供了几种同步资源的方式,包括信号、临界区、事件和互斥体。 私有资源: 1、栈 栈是独享的 2、寄存器 这个可能会误解,因为电脑的寄存器是物理的,每个线程去取值难道不一样吗?其实线程里存放的是副本,包括程序计数器PC
28、for(初始化语句; 布尔表达式; 更新语句) { 正文过程; } 执行顺序: 初始化语句, 仅在循环开始前执行一次; 布亇表达式, 用于决定是否继续执行正文过程, 表达式中异常则结束循环; 正文过程, 如果过程中存在break, return或者异常, 循环结束(不会执行更新语句), 如果遇到continue, 则会执行更新语句后进入下一轮循环; 更新语句, 注意更新语句不做逻辑真假判断, 到这里一轮循环结束; 布亇表达式, 进入新一轮循环;
29、Xms 起始内存
Xmx 最大内存
Xmn 新生代内存
Xss 栈大小。 就是创建线程后,分配给每一个线程的内存大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代大小
收集器设置 -XX:+UseSerialGC:设置串行收集器 -XX:+UseParallelGC:设置并行收集器 -XX:+UseParalledlOldGC:设置并行年老代收集器 -XX:+UseConcMarkSweepGC:设置并发收集器 垃圾回收统计信息 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:filename 并行收集器设置 -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。 -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间 -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n) 并发收集器设置 -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。 -XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
30、重写是子类继承父类方法并对其进行修改,可选择调用父类方法或子类重写后的同名方法
32、Ant和Maven都是基于Java的构建(build)工具。理论上来说,有些类似于(Unix)C中的make ,但没有make的缺陷。
Ant是软件构建工具,Maven的定位是软件项目管理和理解工具。
Ant特点 没有一个约定的目录结构 必须明确让ant做什么,什么时候做,然后编译,打包没有生命周期,必须定义目标及其实现的任务序列 没有集成依赖管理
Maven特点 拥有约定,知道你的代码在哪里,放到哪里去 拥有一个生命周期,例如执行 mvn install 就可以自动执行编译,测试,打包等构建过程 只需要定义一个pom.xml,然后把源码放到默认的目录,Maven帮你处理其他事情拥有依赖管理,仓库管理
33、定义一维数组时,必须显式指明数组的长度;
定义***数组时,其一维数组的长度必须首先指明,其他维数组长度可以稍后指定;
采用给定值初始化数组时,不必指明长度;“[]” 是数组运算符的意思,在声明一个数组时,数组运算符可以放在数据类型与变量之间,也可以放在变量之后。
“abc”保存在常量池,str引用的对象保存在堆里,而java7中又把常量池移到了堆中。
34、有关forward和redirect的描述
1.从地址栏显示来说 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址. redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL. 2.从数据共享来说 forward:转发页面和转发到的页面可以共享request里面的数据. redirect:不能共享数据. 3.从运用地方来说 forward:一般用于用户登陆的时候,根据角色转发到相应的模块. redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站 等. 4.从效率来说 forward:高. redirect:低.
35、HashMap 由数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的 HashMap内部包含了一个默认大小为 16 Entry 类型的数组 table,其中每个Entry 是一个链表,当链表长度大于等于 8 时会将链表转换为红黑树。
36、hashCode()方法和equals()方法的作用其实是一样的,在Java里都是用来对比两个对象是否相等一致。
重写的equals()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高。
hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,
-
equals()相等的两个对象他们的hashCode()肯定相等,也就是用equals()对比是绝对可靠的。
-
hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
37、finally一定会在return之前执行,但是如果finally使用了return或者throw语句,将会使trycatch中的return或者throw失效
38、包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:
1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
2)抽象类不能用来创建对象;
3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。
在其他方面,抽象类和普通的类并没有区别。
39、Servlet生命周期分成3个阶段:
1)初始化阶段:调用init方法
2)响应客户请求:调用service
3)终止:调用destory方法
初始化阶段:在下列时刻servlet容器装载servlet
1 servlet容器启动时,自动装载某些servlet
2 在servlet容器启动后,客户首次向servlet发送请求
3 servlet类文件被更新之后,重新装载servlet
Servlet被装载之后,servlet容器创建一个servlet'对象并调用servlet的init方法,在servlet生命周期内,init方法只能被调用一次。servlet工作原理:客户端发起一个请求,servlet调用service方法时请求进行响应,service对请求的方式进行了匹配,选择调用dopost或者doget等这些方法,然后进入对应方法中调用逻辑层的方法,实现对客户的响应。
响应客户请求:对于用户到达servlet的请求,servlet容器会创建特定于该请求的servletrequest和servletresponse对象,然后调用servlet的service方法,service方法从servletrequest对象中获取客户请求的信息,处理该请求,并且通过servletresponse对象向客户端返回响应信息。
终止:当web应用终止或者servlet容器终止或servlet容器重新装载servlet新实例时,servlet容器会调用servlet对象的destory方法,在destory方法中可以释放servlet占用的资源
41、普通的java对象是通过new关键字把对应类的字节码文件加载到内存,然后创建该对象的。 反射是通过一个名为Class的特殊类,用Class.forName("className");得到类的字节码对象,然后用newInstance()方法在虚拟机内部构造这个对象(针对无参构造函数)。 也就是说反射机制让我们可以先拿到java类对应的字节码对象,然后动态的进行任何可能的操作, 包括 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任意一个对象的方法 这些都是反射的功能。 使用反射的主要作用是方便程序的扩展。 11、Float类和Double类都重写对于的equals方法,在比较之前都会判断是否同属于Float对象或Double对象,如果不是直接返回false,如果是再继续比较对应的数值大小。
42、方法的重写(override)两同两小一大原则: 方法名相同,参数类型相同 子类返回类型小于等于父类方法返回类型, 子类抛出异常小于等于父类方法抛出异常, 子类访问权限大于等于父类方法访问权限。
43、空字符串通过split方法拆分,还是空字符串,长度等于1
全部评论
(1) 回帖