final关键字与数据类型转换
/*
byte b1=1,b2=2,b3,b6,b8;
final byte b4=4,b5=6,b7;
b3=(b1+b2); // 语句1
b6=b4+b5; // 语句2
b8=(b1+b4); // 语句3
b7=(b2+b5); // 语句4
System.out.println(b3+b6);
下列代码片段中,存在编译错误的语句是()
语句2
语句1
语句3
语句4
1、 final关键字可以用于成员变量、本地变量、方法以及类
2、 final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误
3、 你不能够对final变量再次赋值
4、 本地变量必须在声明时赋值
5、 在匿名类中所有变量都必须是final变量
6、 final方法不能被重写
7、 final类不能被继承
8、 没有在声明时初始化final变量的称为空白final变量(blank final variable)
它们必须在构造器中初始化,或者调用this()初始化
不这么做的话,编译器会报错“final变量(变量名)需要进行初始化”
二、数据类型转换
当使用 +、-、*、/、%、运算操作是,遵循如下规则:
如果两个操作数中有一个是double类型的,另一个将会被转换成double类型,并且结果也是double类型
如果两个操作数中有一个是float类型的,另一个将会被转换为float类型,并且结果也是float类型
如果两个操作数中有一个是long类型的,另一个将会被转换成long类型,并且结果也是long类型
否则(操作数为:byte、short、int 、char),两个数都会被转换成int类型,并且结果也是int类型
语句 1 :(b1 + b2) 被转换为int类型 但是 b3仍为 byte ,所以出错
语句 2 :b4 、b5 被声明final 所以类型是不会转换, 计算结果任然是byte ,所以 语句2正确。
语句 3 :(b1 + b4) 结果仍然转换成int 所以语句 3 错误。
语句 4 :(b2 + b5) 结果仍然转换为int , 所以语句4错误。
*/
判断单链表是否有环
/*
算法题:
判断单链表是否有环
思路:设置两个指针,一快一慢
快指针一次性走两步
慢指针一次性走一步
如果有环
则快指针一定能追上慢指针
*/
public boolean hasCycle(ListNode head) {
ListNode quick = head;
ListNode slow = head;
//当快指针能够走到头表示无环
while(quick!=null&&quick.next!=null){
quick = quick.next.next;
slow = slow.next;
if(quick==slow){
return true;
}
}
return false;
}
链式栈插入元素
/*
设链式栈中结点的结构为(data ,link),且top是指向栈顶的指针
若想在链式栈的栈顶插入一个由指针s所指的结点,则应执行( )操作
正确答案: C
top->link=s;
s->link=top->link; top->link=s;
s->link=top; top=s;
s->link=top; top=top->link;
写过类似的代码
是s指向原头指针
接着top指针前移指向s
一定是从头部插入
B选项是将s节点插入到
top节点之后的节点
原top节点没变
A明显错误
D选项原头指针指向第二个节点
导致s和原头节点数据丢失
*/
广义表头尾相同
/*
若广义表A满足Head(A) = Tail (A), 则A为
正确答案: B
( )
( ( ) )
( ( ), ( ) )
( ),( ),( ) )
B中head(A)=();tail(A)=();
C中head(A)=();tail(A)=(());
D中head(A)=);tail(A)=((),()); // 第2个括号
所以重点是求表尾时不要遗忘最外面的那一层括号
例:LS=(a,(b,c,d))
head(LS)=a
tail(LS)=((b,c,d))
head(tail(LS))=(b,c,d)
tail(tail(LS))=()
head(head(tail(LS)))=b
tail(head(tail(LS)))=(c,d)
head(tail(head(tail(LS))))=c
tail(tail(head(tail(LS))))=(d)
head(tail(tail(head(tail(LS)))))=d
tail(tail(tail(head(tail(LS)))))=()
*/
抽象类编写格式
/*
选项中哪一行代码可以替换 //add code here 而不产生编译错误
public abstract class MyClass {
public int constInt = 5;
//add code here
public void method() {}
下面是选项
public abstract void method(int a); // 程序正常运行
consInt=constInt+5; // 报错:不能直接操作实例变量
public int method(); // 报错:没有方法体,返回值不能作为重载的依据,应该是形参,这样就对了public void method(int i){};
public abstract void anotherMethod(){} // 报错:抽象方法不能有方法体
*/
单例模式
/*
下列代码的执行结果是:
class Chinese{
// 第一步,不让外部调用创建对象,所以把构造器私有化,用private修饰
private Chinese(){}
// 第二步,怎么让外部获取本类的实例对象,通过本类提供一个方法,供外部调用获取实例
// 由于没有对象调用,所以此方法为类方法,用static修饰
// static类变量在类加载时就已经实例化好了
// 所以两者实际上指向的是同一个对象
private static Chinese objref =new Chinese();
public static Chinese getInstance() { return objref; }
}
public class TestChinese {
public static void main(String [] args) {
Chinese obj1 = Chinese.getInstance();
Chinese obj2 = Chinese.getInstance();
System.out.println(obj1 == obj2); // true
}
}
*/
无效的变量操作
/*
下列代码:
class Inc {
public static void main(String[] args) {
Inc inc = new Inc();
int i = 0;
inc.fermin(i); // 除非设定返回值并使用参数接收,否则这一步视为值传递没什么用
i= i++; // 这个东西实际上是一个障眼法,i++本质上是个数字本身没变,用i接受还是原来的i
System.out.println(i); // 输出:0
}
void fermin(int i){
i++;
}
}
多态机制
class Base {
public static void main(String[] args) {
Base base = new Son();
base.method();
// base.methodB(); // 编译不通过
}
/*
向上转型,父类的引用无法访问子类独有的方法
而此时base还是属于Base对象
base调用methodB()时Base对象里没有这个方法
所以编译不通过
要想调用的话需要先通过Son son=(Son)base;强制转换
然后用son.methodB()调用就可以了
*/
public void method() {
System.out.println("Base");
}
}
class Son extends Base {
public void method() {
System.out.println("Son");
}
public void methodB() {
System.out.println("SonB"); // 编译时出错
}
/*
向上转型:父类 父类引用 = new 子类,无需强转,会丢弃子类的方法,调用自己的方法时,
如果子类有覆盖方法,就听子类的。如果调用父类没有的方法,编译会出错。
向下转型:子类 子类引用 = (子类)父类引用,要强转,调用子类覆盖的方法。
如果 父类 父类引用 = new 父类; 子类 子类引用 =(子类)父类;这种情况,编译没有错,
运行的时候会提示ClassCastException错误,
如果 父类 父类引用 = new 子类;子类 子类引用 =(子类)父类;这种情况,编译和运行都没有错。
*/
}
多线程同步锁
class NameList {
private List names = new ArrayList();
synchronized void add(String name) {
names.add(name);
}
public static void main(String[] args){
final NameList sl = new NameList();
for (int i = 0; i < 2; i++) {
new Thread(){
public void run() {
sl.add("A");
sl.add("B");
sl.add("C");
sl.printAll();
}
}
}.start();
}
/*
线程1顺利执行完后线程2继续执行,
那么此时的情况就是:线程1连续add这A,B,C,然后立即打印出A B C;
接下来线程2继续执行,即继续add这A,B,C,
那么此时的List中的元素就变成了A B C A B C,
最后立即打印,那么结果就是E答案所示
第一次输出的元素个数大于等于3个,小于等于6个
第二次(最后执行的线程)输出的元素个数必须等于6个
答案G属于线程1执行完前三句add之后线程2插一脚执行了一句add然后线程1再执行
sl.printAll();输出ABCA
接着线程2顺序执行完输出ABCABC
由于计算机运行速度快
大概率出现ABCABCABC
*/
synchronized void printAll() {
for (int i = 0; i < names.size(); i++) {
System.out.print(names.get(i) + "");
}
}
}
程序设计题:自定义注解Id,要求见代码注释
// Id.java
package du;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Id {}
// IdPropertyNotFoundException.java
package du;
public class IdPropertyNotFoundException extends RuntimeException{
public IdPropertyNotFoundException(){}
public IdPropertyNotFoundException(String string){
super(string);
}
}
package du;
import java.lang.reflect.Field;
@Id
public class d844 {
// int id;
String information;
String methods;
public static void main(String[] args) throws ClassNotFoundException{
/*
需求:
假设有这样一个注解叫做Id
这个注解只能出现在类上面
要求这个类中必须要有int类型的id属性
否则报错
*/
/*
首先判断类上是否有Id注解
*/
Class<?> aClass = Class.forName("du.d844");
if (aClass.isAnnotationPresent(Id.class)){
/*
要求类中必须存在int类型的id属性
首先拿到类中所有的属性
*/
Field[] declaredFields = aClass.getDeclaredFields();
boolean haveIntId = false;
for (Field declaredField : declaredFields) {
if ("id".equals(declaredField.getName()) && "int".equals(declaredField.getType().getSimpleName())){
/*
程序运行到此处
表示这个类可以正常运行
*/
haveIntId = true;
break;
}
}
if (!haveIntId){
throw new IdPropertyNotFoundException("Annotation @Id must have int type property id");
}
}
}
/*
所以注解有什么用呢
编译器可以利用注解来探测错误和警告信息
软件工具可以利用注解来生成代码
*/
}