1、自增变量
int i = 1;
i = i++;
int j = i++;
int k = i + ++i * i++;
问i、j、k分别等于?
针对这类题目,
1. 赋值操作=,最后计算;
2. = 右边的从左到右依次压入操作数栈中;
3. 实际先算哪个看符号的优先级;
4. 自增、自减操作都是直接修改变量的值,不需要经过操作数栈;
5. 最后赋值之前,临时结果也是存储在操作数栈中。
所以,本题答案为:i = 4;j = 1;k = 11
逐步分析:
int i = 1;
i = i++; // 先执行=右边的i++,i=1压入操作数栈,i自增为2,再执行赋值操作,将操作数栈的1赋值给i,最终i=1
int j = i++; //同上,j=1, 但是i没有被重新赋值,故i执行自增i=2;
int k = i + ++i * i++;
// i = 2 压入操作数栈中,
// ++i 先自增后赋值,i=3压入操作数栈中;
// i++ 先赋值后自增,i=3先压入操作数栈中,再赋值自增i=4;
// k = 2 + 3 * 3 = 11;
ps:我们可以将前自增和后自增理解为2个不同的函数:
i++:先返回值,i再自增
++i:i自增后再返回
2、单例模式(Singletion)
Singletion:单例设计模式,即某个类在整个系统中只能有一个实例对象可以被获得和使用的代码模式,是软件开发中最常用的设计模式之一。
例如:代表JVM运行的Runtime类
要点:
· 某个类只能有一个实例;
- 构造器私有化
· 必须自行创建这个实例;
- 含有一个该类的静态变量来保存这个唯一实例
· 必须自行向整个系统提供这个实例;
- 对外提供该类获取该对象实例的方法:直接暴露、用静态变量的get方法获取
常见形式:
· 饿汉式:在类初始化时直接创建对象,不存在线程安全问题
- 直接实例化饿汉式(简单直观)
- 枚举式(最简洁)
- 静态代码块饿汉式(适合复杂实例化)
//直接实例化饿汉式
public class Singleton{
public static final Singletion INSTANCE = new Singleton();
private Singleton(){
}
}
//枚举式
public enum Singleton{
INSTANCE
}
//静态代码块式
public class Singleton{
public static final Singleton INSTANCE;
private String info; //info存储在配置文件或资源文件中
static{
try{
Properties pro = new Properties();
pro.load(Singleton.class.getClassLoader().getResourceAsStream("xxx.xxx");
INSTANCE = new Singleton(pro.getProperty("info"));
}catch(IOException e){
throw new RuntimeException(e);
}
}
private Singleton(String info){
this.info = info;
}
public String getInfo(){
return this.info;
}
}
· 懒汉式:延迟创建对象
- 线程不安全(单线程)
- 线程安全(多线程)
-静态内部类形式(多线程)
//非线程安全
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
instance = new Singleton();
}
return instance;
}
}
//线程安全
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronzied(Singleton.class){
if(instance == null){
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
instance = new Singleton();
}
}
}
return instance;
}
}
//静态内部类式
/*
在内部类被加载和初始化时,才创建INSTANCE实例对象;
静态内部类不会随着外部类的加载和初始化而初始化,它需要单独地去加载和初始化;
因为是在内部类加载和初始化时,才创建实例,所以是线程安全的。
*/
public class Singleton{
private Singleton(){}
private static class Inner{
private static final Singletion INSTANCE = new Singletion();
}
public Singleton getInstance(){
return Inner.INSTANCE;
}
}
3、类初始化和实例化
/*
父类的初始化:
1)j = method()
2)父类的静态代码块
父类实例初始化:
1) super()
2)i = test()
3)父类的非静态代码块
4)父类无参构造器(最后)
非静态方法前面其实有一个默认对象this
this在构造器表示的是正在创建的对象,这里正在创建的是Son对象,所以运行的是Son.test()---面向对象多态
创建第二个Son实例对象,类初始化只执行一次,实例化初始化在执行一次
*/
public class Father{
private int i = test();
private static int j = method();
static{
sout("1");
}
Father(){
sout("2");
}
{
sou("3");
}
public int test(){
sout("4");
return 1;
}
public static int method(){
sout("5");
return 1;
}
}
/*
子类的初始化:
1)j = method()
2)子类的静态代码块
先初始化父类 (5)(1)
再初始化子类 (10)(6)
子类实例初始化:
1) super() (9)(3)(2)
2)i = test() (9)
3)子类的非静态代码块 (8)
4)子类无参构造器(最后) (7)
*/
public class Son extends Father{
private int i = test();
private static int j = method();
static{
sout("6");
}
Son(){
sout("7");
}
{
sou("8");
}
public int test(){
sout("9");
return 1;
}
public static int method(){
sout("10");
return 1;
}
public static void main(String[] args){
Son s1 = new Son();
sout();
Son s2 = new Son();
}
}
//out
5 1 10 6 9 3 2 9 8 7
9 3 2 9 8 7
要理清这类考题,需要弄清3个考点:
1. 类初始化过程
1. 一个类要创建实例需要先加载并初始化该类
· main 方法所在的类需要先加载和初始化;
2. 一个子类需要初始化需要先初始化父类
3. 一个类初始化就是执行<clinit>()方法
2. 实例初始化过程
1. 实例初始化就是执行<init>()方法
3. 方法的重写
1. 哪些不能被重写
· final方法
· 静态方法
· private 等子类不可见方法
2. 对象的多态
子类如果重写了父类的方法,通过子类调用的一定是重写后的方法;
4、方法的参数传递机制
1. 形参是基本数据类型
传递数据值
2. 实参是引用数据类型
传递地址值
特殊的类型:String、 包装类(Integer)等对象不可变性