Java的一些总结(初)

根据HOW2J回顾了下JAVA的基本概念,并计划以此进行java后端的学习。

1.利用布尔变量结束外部循环,迭代用throw

public class HelloWorld {
    public static void main(String[] args) {
        boolean breakout = false; //是否终止外部循环的标记
        for (int i = 0; i < 10; i++) {

            for (int j = 0; j < 10; j++) {
                System.out.println(i + ":" + j);
                if (0 == j % 2) {
                    breakout = true; //终止外部循环的标记设置为true
                    break;
                }
            }
            if (breakout) //判断是否终止外部循环
                break;
        }

    }
}

2.用异或^来判断是否相同,同或为^!

A^A = 0
A^0 = A

3.四种访问修饰符的权限

这里写图片描述
那么什么情况该用什么修饰符呢?
从作用域来看,public能够使用所有的情况。 但是大家在工作的时候,又不会真正全部都使用public,那么到底什么情况改用什么修饰符呢?

  1. 属性通常使用private封装起来
  2. 方法一般使用public用于被调用
  3. 会被子类继承的方法,通常使用protected
  4. package用的不多,一般新手会用package,因为还不知道有修饰符这个东西

再就是作用范围最小原则
简单说,能用private就用private,不行就放大一级,用package,再不行就用protected,最后用public。 这样就能把数据尽量的封装起来,没有必要露出来的,就不用露出来了

4.Java的参数初始化——静态代码块;构造代码块;构造代码区别

通过下面的代码可以很好的理解初始化的先后顺序:

/*
 * 静态代码块;构造代码块;构造代码区别
 * */
class Solution{
    static {
        prt("1---static");
    }

    public Solution(){
        prt("2---无参构造函数开始执行");
    }
    public Solution(String a){//构造函数,有参
        prt(a);
    }

    static void prt(String a){
        System.out.println(a);
    }

    {
        prt("3---no static,非静态的构造代码块");
    }



    public static void main (String[] age){     
        Solution c1=new Solution("4---有参构造函数开始执行");
        Solution c=new Solution();

    }
}

运行结果如下:

1---static          //只运行一次
3---no static,非静态的构造代码块
4---有参构造函数开始执行
3---no static,非静态的构造代码块  //运行了两次,可以看出每次类进行实例化都会对非静态的构造代码块进行实现,然后再去调用具体方法
2---无参构造函数开始执行

5.单例模式

单例模式指仅仅需要一个实例,不允许外部创建该类的新实例。单例模式分两种,一种是直接加载(饿汉模式),一种是延时加载(懒汉模式)
具体实现如下:
饿汉模式:

  public class Singleton {
    private final static Singleton INSTANCE = new Singleton();

    // Private constructor suppresses   
    private Singleton() {}

    // default public constructor
    public static Singleton getInstance() {
        return INSTANCE;
    }
  }

懒汉模式:

  public class Singleton {
    private static volatile Singleton INSTANCE = null;

    // Private constructor suppresses 
    // default public constructor
    private Singleton() {}

    //thread safe and performance  promote 
    public static  Singleton getInstance() {
        if(INSTANCE == null){
             synchronized(Singleton.class){
                 //when more than two threads run into the first null check same time, to avoid instanced more than one time, it needs to be checked again.考虑线程安全
                 if(INSTANCE == null){ 
                     INSTANCE = new Singleton();
                  }
              } 
        }
        return INSTANCE;
    }
  }

特点:

饿汉式,是立即加载的方式,无论是否会用到这个对象,都会加载。
如果在构造方法里写了性能消耗较大,占时较久的代码,比如建立与数据库的连接,那么就会在启动的时候感觉稍微有些卡顿。

懒汉式,是延迟加载的方式,只有使用的时候才会加载。 并且有线程安全的考量
使用懒汉式,在启动的时候,会感觉到比饿汉式略快,因为并没有做对象的实例化。 但是在第一次调用的时候,会进行实例化操作,感觉上就略慢。

这个是面试的时候经常会考的点,面试题通常的问法是: 什么是单例模式?

回答的时候,要答到三元素
1. 构造方法私有化
2. 静态属性指向实例
3. public static的 getInstance方法,返回第二步的静态属性

6.对象的转型

关键就是看最后引用变量是什么类型,因为之后调用的是引用变量。引用变量对应的类比赋予的类的范围窄就没问题,范围宽就会出错。

a.子类(实例的类型)转父类(引用变量的类型)

没问题,因为父类的范围窄
所以我们常会遇到List<E> list = new ArrayList<>();这样的例子,不过要注意的是在这种情况下,list只能调用List类实现的方法,而不能使用ArrayList的方法。但是如果该方法为List的子类ArrayList和LinkedList同时实现了,如sort(),则当List类型的引用变量list.sort()时,系统就会自动根据list具体指向哪个子类来判断使用谁的方法。在这里就是ArrayList 的方法。(这也就是多态)

b.父类转子类

可能存在问题

c.类转接口

没问题,因为引用变量为接口类型,能使用的都是接口定义方法,这在实现了接口的类中都有定义。
注意:在调用接口时候,我们常会使用接口的名称 变量 = new 实现接口的类名();Comparator comp = new CharaterComparator();在左边的这句代码中,Character是一个实现了Comparator接口的类,但是他也仅仅用于实现该接口,因此,在实例化时,我们会写Comparator comp而不是CharaterComparator comp,因为类转接口十分方便我们确实该类的作用是用于实现接口而不是其他功能。

7.重载、重写、隐藏、遮蔽、遮掩的区别浅析

对于隐藏来说,可以参见下文:
作者:黄恩雄
链接:https://www.zhihu.com/question/36655314/answer/213030995
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1、子类继承父类的时候,会在子类的构造函数中调用父类的构造函数,这是一个很关键的地方,这意味着子类是通过父类的构造函数来继承获取父类的成员(变量和方法)。而Static关键字修饰的内容是属于类的,优先于类对象的创建而创建。也就是子类如果创建了一个和父类一样的静态成员,父类再通过子类对象将父类的该静态成员遗传给子类,应该是会覆盖子类的静态成员。这样的话子类的子类也会被子类的静态成员所覆盖,应该会导致所有子类都使用同一个父类静态成员(静态成员传导)。

2、根据多态原理,父类变量接收子类对象时如果父类的静态成员被子类覆盖应该调用子类的静态成员(多态)。1和2形成冲突。实际测试中,通过一个demo——Father,Son,GrandSon中均定义各自的相同静态方法,改写方法体中的内容,然后使用多态对各个方法进行调用,再使用本身的类对象进行调用,其结果是:如果子类重写了父类的静态方法,使用多态由父类变量接收子类对象时,该父类变量调用的是父类自己的静态方法(没有多态);如果子类重写了父类的静态方法,使用子类本身类型的变量接收子类的对象,子类调用自己的静态方法(没有传导);如果子类没有重写父类的静态方法,使用子类本身类型的变量接收子类的对象会调用父类的静态方法(继承)。所以,我认为静态成员的继承应该是执行变量类型就近原则:如果父类和子类都有相同的静态成员方法时,父类变量就执行父类静态成员;子类变量就执行子类静态成员。如果子类没有相应的静态成员方法,子类变量就执行父类的静态成员。子女也总是混不下去了才会啃老吧。。。

8.super和this的区别

1.super关键字表示超(父)类的意思。this变量代表对象本身.
2.super访问父类被子类隐藏的变量或覆盖的方法。当前类如果是从超类继承而来的,当调用super.XX()就是调用基类版本的XX()方法。其中超类是最近的父类。
3.调用super() 父类构造函数的时候只能调用在子类构造函数的第一行。这就是说,在子类继承父类时,Java会隐式的调用super.父类构造器;来完成继承操作。
4.this只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现this。并且this只和特定的对象关联,而不和类关联,同一个类的不同对象有不同的this

9.抽象Abstract

  • 含有抽象方法的类必须为抽象类
  • 抽象类可以含有非抽象方法
  • 抽象类不能被实例化

接口和抽象类的区别

接口和抽象类都不可以实例化,但是可以将他们类型的引用变量实例化为其子类(子类要实现抽象方法),比如对于父类Father,子类Son,接口Interface这三个类,可以这么定义:

Father fa = new Son();
Interface Inter = new Son();

我认为这么做的方法是为了告诉读者该变量具体的使用是父类/接口内的东西,而非子类。

10.内部类

内部类分为非静态内部类;静态内部类;本地类;匿名内部类

  • 内部类可以方便的调用外部类的变量
  • 非静态内部类的实例化要在实例化外部类之后,即每个非静态内部类的实例都要跟在一个外部类实例之后,不能单独创建
  • 静态内部类的实例化可以直接进行,不需要等外部类进行实例化,除了可以使用外部类的静态变量,静态内部类可以看作一个独立的类
  • 本地类就是定义在外部类的方法等成员变量中的内部类
  • 匿名内部类常用于做接口的实现类,在jdk8后可以用lambda表达式代替

关于匿名内部类引用外部成员变量的时候外部引用参数要final的原因详见:java为什么匿名内部类的参数引用时final?
主要原因就是闭包的存在,在闭包内,java其实是悄悄拷贝了一份外部参数给匿名内部类的变量,如果外部参数不final,一旦改变,将导致不能和匿名内部类中的参数一致。

思考:Map和Map.Entry是什么关系?

猜你喜欢

转载自blog.csdn.net/timemagician/article/details/79130878