java基础第一式(结合刷题)
链接:对文件名为Test.java的java代码描述正确的是()__牛客网
来源:牛客网
子类的构造方法总是先调用父类的构造方法,如果子类的构造方法没有明显地指明使用父类的哪个构造方法,子类就调用父类不带参数的构造方法。
而父类没有无参的构造函数,所以子类需要在自己的构造函数中显示的调用父类的构造函数。
子类构造方法在调用时必须先调用父类的,由于父类没有无参构造,必须在子类中显式调用,修改子类构造方法如下即可: public Derived(String s){ super("s"); System.out.print("D"); }
---
byte short int long float double boolean char
1 2 4 8 4 8 1 2
----
既然是要捕获在 编译期 和 运行期
首先编译期在有些方法是必须要进行 try catch
而运行期可以手动添加 try catch
运行期间出现的异常都可以使用RuntimeException这个是运行期间所有异常的 “组长”
但是编译期就多了,他们没有这个所谓的 “组长”,但是它们上面还有个 “班长”(Exception)也就时 “组长” 的 “头儿”
所以可以使用这个 “班长”(Exception)解决这两个组的异常
因为error是系统出错,catch是无法处理的,难以修复的,
RuntimeException不需要程序员进行捕获处理,
error和exception都是throwable的子类,我们只需要对exception的实例进行捕获即可
---
解析:执行顺序
父类静态代码块 ->子类静态代码块 ->父类非静态代码块 -> 父类构造函数 -> 子类非静态代码块 -> 子类构造函数。
正确选项是 A
1,字符串在java中存储在字符串常量区中(同一份字符串常量在内存中只有一份) 2,==判断的是对象引用是否是同一个引用,判断字符串相等要用equals方法 首先判断a==MESSAGE 同一份字符串常量在内存中只有一份,因此是同一地址,返回true 再次比较(b+c)==MESSAGE 这相当于 new String(b+c)==MESSAGE 这里new了一个String对象,所以 返回false
A
/ \
B C
/
D
D属于B,D不属于C,D属于D, D属于A,故有三个 true;
java命名规则
- Java 标识符有如下命名规则:
-
- 由26个英文字母大小写,数字:0-9 符号:_ $ 组成
- 标识符应以字母、_ 、$开头。
- 标识符不能是关键字。
- Java中严格区分大小写
synchronized可以修饰方法、代码块或对象,并不修饰变量。
1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
public class Demo05 { public static void main(String[] args) { A a = new B(); B b = new B(); System.out.println("result = " + a.func1(100,50)); System.out.println("result = " + b.func1(100,50)); } } class A { public int func1(int a,int b) { return a-b; } } class B extends A{ public int func1(int a,int b) { return a+b; } }
其实很简单,涉及转型的题目,分为向上或者向下转型。
关键的来了,不论向上或者向下转型,都是一句话,“编译看左边,运行看右边”。也就是编译时候,会看左边引用类型是否能正确编译通过,运行的时候是调用右边的对象的方法。
就本题来说,编译时候会发现左边满足条件所以编译通过,运行时候又会调用右边也就是 class B 的方法,所以答案都是150。
通过阅读源码可以知道,string与stringbuffer都是通过字符数组实现的。
其中string的字符数组是final修饰的,所以字符数组不可以修改。
stringbuffer的字符数组没有final修饰,所以字符数组可以修改。
string与stringbuffer都是final修饰,只是限制他们所存储的引用地址不可修改。
至于地址所指内容能不能修改,则需要看字符数组可不可以修改。
----------
final修饰的成员变量为基本数据类型时,赋值后无法改变。当final修饰的为引用变量时, 在赋值后其指向地址无法改变,但对象内容可以改变。感觉应该有一定关系 另外, 对于该题,final修饰类只是限定类不可被继承,而非限定了其对象是否可变 StringBuilder , StringBuffer ,String 都是 final 的,但是为什么StringBuilder , StringBuffer 可以进行修改呢,因为不可变包括的是,引用不可变以及对象不可变,而这三个都是属于引用不可变, (也就是地址不要变,里面的内容随心所欲),而StringBuilder , StringBuffer 中都包含右append方法, 可对对象中的内容进行增加。 而String a="123"+new String("456");实际上底层是用了一个StringBuffer 进行append;
数组引用类型的变量的默认值为 null。当数组变量的实例后,如果没有没有显示的为每个元素赋值,Java 就会把该数组的所有元素初始化为其相应类型的默认值。
int型的默认值为0
在类方法中调用本类的类方法可直接调用。 实例方法也叫做对象方法。 类方法是属于整个类的,而实例方法是属于类的某个对象的。 由于类方法是属于整个类的,并不属于类的哪个对象,所以类方法的方法体中不能有与类的对象有关的内容。即类方法体有如下限制:
(1) 类方法中不能引用对象变量;
(2) 类方法中不能调用类的对象方法;
(3) 在类方法中不能使用super、this关键字。
(4)类方法不能被覆盖。 如果违反这些限制,就会导致程序编译错误。 与类方法相比,对象方法几乎没有什么限制:
(1) 对象方法中可以引用对象变量,也可以引用类变量;
(2) 对象方法中可以调用类方法;
(3) 对象方法中可以使用super、this关键字。
This和super在静态方法中不能使用。 类名调用是对静态方法或变量的一个区分性标志。
同一个类中,方法可以调用private 修饰的变量和方法。
HashMap可以插入null的key或value,插入的时候,检查是否已经存在相同的key,
如果不存在,则直接插入,如果存在,则用新的value替换旧的value,在本题中,第一条put语句,会将key/value对插入HashMap,而第二条put,因为已经存在一个key为name的项,所以会用新的value替换旧的vaue,因此,两条put之后,HashMap中只有一个key/value键值对。那就是(name,jack)。所以,size为1.
Float是类,float不是类.
查看JDK源码就可以发现Byte,Character,Short,Integer,Long,Float,Double,Boolean都在java.lang包中.
Float正确复制方式是Float f=1.0f,若不加f会被识别成double型,double无法向float隐式转换.
Float a= new Float(1.0)是正确的赋值方法,但是在1.5及以上版本引入自动装箱拆箱后,会提示这是不必要的装箱的警告,通常直接使用Float f=1.0f.
在Java中,可以将一个类定义在另一个类里面或者一个方法里边,这样的类称为内部类,广泛意义上的内部类 一般包括四种:成员内部类,局部内部类,匿名内部类,静态内部类 。 1.成员内部类 (1)该类像是外部类的一个成员,可以无条件的访问外部类的所有成员属性和成员方法 (包括private成员和静态成员); (2)成员内部类拥有与外部类同名的成员变量时,会发生隐藏现象,即默认情况下访问的是成员内部类中的 成员。如果要访问外部类中的成员,需要以下形式访问: 【外部类.this.成员变量 或 外部类.this.成员方法】; (3)在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的 引用来访问; (4)成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个 外部类的对象; (5)内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。 如果成员内部类用private修饰,则只能在外部类的内部访问;如果用public修饰,则任何地方都能访问; 如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问; 如果是默认访问权限,则只能在同一个包下访问。外部类只能被public和包访问两种权限修饰。 2.局部内部类 (1)局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的 访问仅限于方法内或者该作用域内; (2)局部内部类就像是方法里面的一个局部变量一样,是不能 有public、protected、private以及static修饰符的。 3.匿名内部类 (1)一般使用匿名内部类的方法来编写事件监听代码; (2)匿名内部类是不能有访问修饰符和static修饰符的; (3)匿名内部类是唯一一种没有构造器的类; (4)匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。 4.内部静态类 (1)静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似; (2)不能使用外部类的非static成员变量或者方法。
被static修饰的变量称为静态变量,
静态变量属于整个类,而局部变量属于方法,只在该方法内有效,所以static不能修饰局部变量
wait()、notify()和notifyAll()是 Object类 中的方法 从这三个方法的文字描述可以知道以下几点信息: 1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。 2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁) 3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在 等待这个对象的monitor,则只能唤醒其中一个线程; 4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程; 有朋友可能会有疑问:为何这三个不是Thread类声明中的方法,而是Object类中声明的方法(当然由于Thread 类继承了Object类,所以Thread也可以调用者三个方法)?其实这个问题很简单,由于每个对象都拥有 monitor(即锁),所以让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。而不是用 当前线程来操作,因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。 上面已经提到,如果调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁) 因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。 调用某个对象的wait()方法,相当于让当前线程交出此对象的monitor,然后进入等待状态,等待后续再次 获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行, 但它并不释放对象锁); notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的monitor的话, 则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知。 同样地,调用某个对象的notify()方法,当前线程也必须拥有这个对象的monitor,因此调用notify()方法 必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。 nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。 Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作, 相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作 更加安全和高效。因此通常来说比较推荐使用Condition,在阻塞队列那一篇博文中就讲述到了, 阻塞队列实际上是使用了Condition来模拟线程间协作。 Condition是个接口,基本的方法就是await()和signal()方法; Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition() 调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和 lock.unlock之间才可以使用Conditon中的await()对应Object的wait(); Condition中的signal()对应 Object的notify(); Condition中的signalAll()对应Object的notifyAll()
public class Person{ private String name = "Person"; int age=0; } public class Child extends Person{ public String grade; public static void main(String[] args){ Person p = new Child(); System.out.println(p.name); } } Java中对字段属性是静态绑定,方法成员是动态绑定,这里错在:在子类中试图访问父类的private字段, 所以编译不通过,将private去掉就可访问,不是动态绑定的问题,它本来就属于静态绑定
方法重写遵循的原则 (两同两小一大原则)
补充一下,两同两小一大原则,即:
方法名相同,参数类型相同
子类返回类型小于等于父类方法返回类型,
子类抛出异常小于等于父类方法抛出异常,
子类访问权限大于等于父类方法访问权限。
类的加载包括:加载,验证,准备,解析,初始化。
选项A:生成java.lang.Class对象是在加载时进行的。生成Class对象作为方法区这个类的各种数据的访问入口。
选项B:既然是对象成员,那么肯定在实例化对象后才有。在类加载的时候会赋予初值的是类变量,而非对象成员。
选项C:这个会调用。可以用反射试验。
选项D:类方法解析发生在解析过程。
1.final修饰变量,则等同于常量
2.final修饰方法中的参数,称为最终参数。
3.final修饰类,则类不能被继承
4.final修饰方法,则方法不能被重写。
final 不能修饰抽象类,final修饰的方法可以被重载 但不能被重写
<<表示左移位
>>表示带符号右移位
>>>表示无符号右移
但是没有<<<运算符
String是final修饰的,不可变
运行速度StringBuilder>StringBuffer>String
StringBuffer是线程安全的
线程的互斥锁机制:synchronized,lock,condition
一.final 如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明 为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。 被声明为final的变量必须在new一个对象时初始化(即只能在声明变量或构造器或代码块内初始化), 而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能覆盖(重写)。 二.finally 在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行 然后控制就会进入finally 块(如果有的话)。 三.finalize 方法名。Java 技术允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。 这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在Object 类中定义的,因此 所有的类都继承了它。子类覆盖 finalize()方法以整理系统资源或者执行其他清理工作。 finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。 注意:finalize不一定被jvm调用,只有当垃圾回收器要清除垃圾时才被调用。
hashCode()方法和equals()方法的作用其实是一样的,在Java里都是用来对比两个对象是否相等一致。
那么equals()既然已经能实现对比的功能了,为什么还要hashCode()呢?因为重写的equals()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高。
那么hashCode()既然效率这么高为什么还要equals()呢? 因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,
所以我们可以得出:
1.equals()相等的两个对象他们的hashCode()肯定相等,也就是用equals()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
所有对于需要大量并且快速的对比的话如果都用equals()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equals(),如果equals()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
静态语句块中x为局部变量,不会影响到静态变量x的值
x和y 为静态变量,默认初始值为0,属于当前类,其值的改变会影响到整个类的运行。
结果是3
创建并启动线程的过程为:定义线程——>实例化线程——>启动线程
要写一个线程类,可以继承Thread方法,然后override他的run()方法,另外一种方法是实现Runnable的接口,即为实现run()方法
start()是启动一个线程的方法。
1、接口中的方法必须是public,并且默认情况下方法也是public的,B中是private,错
2、接口中的方法是为其他类提供实现的标准,只能有方法头,没有方法体
- 编译器将Java源代码编译成字节码class文件
- 类加载到JVM里面后,执行引擎把字节码转为可执行代码
- 执行的过程,再把可执行代码转为机器码,由底层的操作系统完成执行。
只有char变成 int 的时候才会变为对应的assic码
--------------------------------------------------------------
1.静态先行。
2.静态成员变量的显示初始化和静态代码块按照代码的先后顺序执行。
3.静态的变量在内存中只保存一份。
final修饰的类为终态类,不能被继承,而抽象类是必须被继承的才有其意义的,因此,final是不能用来修饰抽象类的。
final修饰的方法为终态方法,不能被重写。而继承抽象类,必须重写其方法。
抽象方法是仅声明,并不做实现的方法。
class Value{ public int i = 15; } public class Demo7 { public static void main(String[] args) { Demo7 t = new Demo7(); t.first(); } private void first() { int i = 5; Value v = new Value(); v.i = 25; second(v,i); System.out.println(v.i); } private void second(Value v, int i) { i = 0; v.i = 20; Value val = new Value(); v = val; System.out.println(v.i+" "+i); } }
考察 值的传递和引用传递,
JAVA中原始数据类型都是值传递,传递的是值得副本,形参的改变不会影响到是实参的值,引用传递,传递的是引用类型数据,包括String,数组,列表,map,类对象等类型,形参与实参指向的是同一内存地址,故形参的改变会影响到实参的值。
1、为了更好地组织类,Java提供了包机制。包是类的容器,用于分隔类名空间。如果没有指定包名,所有的示例都属于一个默认的无名包。Java中的包一般均包含相关的类,java是跨平台的,所以java中的包和操作系统没有任何关系,java的包是用来组织文件的一种虚拟文件系统。A错
2、import语句并没有将对应的java源文件拷贝到此处仅仅是引入,告诉编译器有使用外部文件,编译的时候要去读取这个外部文件。B错
3、Java提供的包机制与IDE没有关系。C错
4、定义在同一个包(package)内的类可以不经过import而直接相互使用。
&运算符:两个数都转为二进制,然后从两个数的最高位进行与运算,两个都为真(1),结果才为真(1), 否则为假(0) 13:01101 17:10001 结果:00001,既为1
当final修饰的成员变量为基本数据类型的时候,在赋值之后无法改变
当final修饰的成员变量为引用类型的时候,在赋值后指向地址无法改变,但是对象的内容还是可以改变
final修饰的成员变量在赋值的时候可以有三种方式:
1.在声明时候直接赋值 2.在构造器中赋值 3.在初始代码块中赋值。
CountDownLatch:一个或者多个线程,等待其他线程完成某件事情之后才能执行。
CyclicBarrier:多个线程互相等待,直到到达同一同步点,在继续一起执行。
Semaphore:信号量,可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源
Future:表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或者失败后作出相应的操作
Map没有实现Collection,但是Map也是集合
Collection是java容器对象的顶层接口,想List,Set等都实现了Collection接口
Collections是java集合对象的工具类,提供了有关常用集合操作的静态方法
直接上源码:这样够清楚吗? public interface Collection<E> extends Iterable<E> { Collection接口继承了Iterable 接口 } public class Collections { private Collections() { } }