Moosphan/Android-Daily-Interview

2019-05-23:分别讲讲 final,static,synchronized 关键字可以修饰什么,以及修饰后的作用?

MoJieBlog opened this issue · 16 comments

2019-05-23:分别讲讲 final,static,synchronized 关键字可以修饰什么,以及修饰后的作用?

static

  1. static 方法
    static 方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有 this 的,因为它不依附于任何对象,既然都没有对象,就谈不上 this 了。
public class StaticTest {   
    public static void a(){
    }
    public static void main(String[]args){
        StaticTest.a();
    }     
}
  1. static 变量
    static 变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
  2. static 代码块
    static 关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static 块可以置于类中的任何地方,类中可以有多个 static 块。在类初次被加载的时候,会按照 static 块的顺序来执行每个 static 块,并且只会执行一次。
public class StaticTest {
    private static int a ;
    private static int b;
    static {
        a = 1;
        b = 2;
    }

final

  1. final 变量
    凡是对成员变量或者本地变量(在方法中的或者代码块中的变量称为本地变量)声明为 final 的都叫作 final 变量。final 变量经常和 static 关键字一起使用,作为常量。
   private final int aa = 1;
    static {
        a = 1;
        b = 2;
    }
    private void init(){
        aa = 2;//报错编译器会提示 不能赋值。。
    }
  1. final 方法
    final 也可以声明方法。方法前面加上 final 关键字,代表这个方法不可以被子类的方法重写。如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为 final。final 方法比非 final 方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
    public static void main(String[]args){
        StaticTest.a();
    }
    class StaticTest2 extends StaticTest{
        public  final void a(){ //这边就会编译器提示不能重写
        }
    }
  1. **final 类 **
    其实更上面同个道理,使用 final 来修饰的类叫作 final 类。final 类通常功能是完整的,它们不能被继承。Java 中有许多类是 final 的,譬如 String,Interger 以及其他包装类。

synchronized

synchronized 是 Java 中解决并发问题的一种最常用的方法,也是最简单的一种方法。synchronized 的作用主要有三个:

  • 确保线程互斥的访问同步代码
  • 保证共享变量的修改能够及时可见
  • 有效解决重排序问题。
  1. synchronized 方法
    有效避免了类成员变量的访问冲突:
    private synchronized void init(){
        aa = 2;
    }
  1. synchronized 代码块
    这时锁就是对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的 instance 变量(它得是一个对象)来充当锁。
   public  final void a(){
       synchronized (lock){
             //代码
       }
    }
    @Override
    public void run() {
    }

final :可以修饰 类,方法,字段。

修饰类:该类不会被继承。

修饰方法:该方法不能被重写。

修饰字段:被修饰的 字段必须 赋初始值,并且不能被改变。如果字段是引用类型的。那么他将不能引用别		的对象,但是当前的对象内的 属性值是可以改变的。

static :可以修饰内部类,方法,字段。

修饰内部类:被static修饰 的内部类可以直接作为一个 普通的类来使用,而不需先实例一个外部列。

修饰方法:调用该方法的时候只需要类名 . 方法就可以直接调用,不需要创建对象。

修饰字段:通过类名 . 的方式可以直接 获取 或者 赋值。

synchronized 可以修饰 方法,代码块

修饰方法:被 synchronized 修饰方法方法在同一时刻只能被一个线程访问。其他线程将会被阻塞,直到当前线程释放锁。

修饰代码块:其实和修饰方法差不多,只不过 修饰代码块可以 使用 类锁。方法如果要使用类锁,只能设置为静态的方法。

final, static都可以修饰类,方法,字段;synchronized可以修饰方法,代码块。

final修饰类:该类不会被修饰。static修饰内部类:被static修饰 的内部类可以直接作为一个 普通的类来使用,而不需先实例一个外部类。final方法:该方法不能重写;static方法:修饰方法只需要类名,方法就可以直接调用,不需要创建对象。final修饰字段:被修饰的字段必须赋初始值,并且不能被改变。如果字段是引用类型的。那么他将不能引用别的对象,但是当前的对象内的属性值是可以改变的
static修饰字段:通过类名的方式就可以直接获取
 synchronized修饰方法: 被synchronized修饰方法在同一时刻只能被一个线程访问;synchronized代码块:获取那把锁lock对象后就可以获取锁内代码。 方法只能设置为静态的方法。

前面的大佬说的都挺好的 我也复习一哈

final 可修饰 类、变量、方法

修饰类,不可被继承,比如String类
修饰变量,不可被改变,必须给定初值
修饰方法,不可被重写

static 可修饰 类、变量、方法

修饰内部类,不需要外部类实例,当做普通类使用
修饰变量,通过类名直接调用
修饰方法,通过类名直接调用

synchronized 代码块、方法,看具体代码位置,来实现代码的同步
可参考 synchronized 使用详解

。补充一些
最后
被最终修饰的变量,在编译时时已经确定了其值,那么它就相当于一个宏变量,程序会将使用到该变量值的地方都替换为该值;被最终修饰,编译时可以确定值的变量,不会随类而加载。

静是一个特殊的关键字,它可用于修饰方法,成员变量等成员.static修饰的成员表明他属于这个类本身,而不属于该类的单个实例。而我们非静态修饰的变量它属于的是实例的变量,所以为static成员不能直接访问静态成员。”
同步
我们一般称之为加锁,用于简单解决并发时数据操作问题,很简单的案例,比如银行取钱问题。同步
方法:
Java的每一个对象都有一个内部锁,如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。也就是说,要调用该方法,线程必须获得内部的对象锁。
同步代码块
在方法中,只有某些地方需要加锁 那么就可以使用同步代码块。而不是全部加锁。但很多人都说同步代码块非常脆弱,这点并不是很理解?

静态的

  1. 静方法
    **static**方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。
public  class  StaticTest {   
     public  static  void  a(){
    }
    public  static  void  mainString [] args){
         StaticTest个();
    }     
}
  1. static变量
    **static**变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
  2. static代码块
    **static**关键字还有一个比较关键的作用就是用来形成静态代码块以优化程序性能.static块可以置于类中的任何地方,类中可以有多个静态块。在类初次被加载的时候,会按照静态块的顺序来执行每个静态块,并且只会执行一次。
public  class  StaticTest {
     private  static  int a;
    private  static  int b;
    静态 {
        a =  1 ;
        b =  2 ;
    }

最后

  1. final变量
    凡是对成员变量或者本地变量(在方法中的或者代码块中的变量称为本地变量)声明为final的都叫作最终变量.final变量经常和静态关键字一起使用,作为常量。
   private  final  int aa =  1 ;
    静态 {
        a =  1 ;
        b =  2 ;
    }
    private  void init(){
        aa =  2 ; //报错编译器会提示不能赋值.. 
    }
  1. 最终方法
    final也可以声明方法。方法前面加上final关键字,代表这个方法不可以被子类的方法重写。如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为final.final方法比非最终方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
    public  static  void mainString [] args){
         StaticTest个();
    }
    class  StaticTest2  扩展 StaticTest {
         public   final  void  a(){ //这边就会编译器提示不能重写
        }
    }
  1. ** final类**
    其实更上面同个道理,使用final来修饰的类叫作final类.final类通常功能是完整的,它们不能被继承.Java中有许多类是final的,譬如String,Interger以及其他包装类。

同步

synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法.synchronized的作用主要有三个:

  • 确保线程互斥的访问同步代码
  • 保证共享变量的修改能够及时可见
  • 有效解决重排序问题。
  1. synchronized方法
    有效避免了类成员变量的访问冲突:
    private  synchronized  void init(){
        aa =  2 ;
    }
  1. 同步代码块
    这时锁就是对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的实例变量(它得是一个对象)来充当锁。
   public   final  void a(){
        synchronizedlock){
              //代码
       }
    }
    @Override 
    public  void run(){
    }

你好,我有一个疑问,在学习synchronized时,很多人都说同步代码块是非常脆弱的,但是我并不明白为什么说它脆弱呢?

  • ##final
    final可以用来修饰类、方法、变量分别有不同的意义。修饰class表示这个累不可以被继承扩展、修饰变量表示这个变量是不可修改的、修饰函数表示这个函数不可以被重写 .
  1. 我们可以将方法和类声明为final,明确告诉别人这些行为是不允许修改的,java中的一些核心类库就是这样设计的,这样可以有效避免API使用者更改基础功能,保证安全。

  2. 将变量声明为final,可以用于保护只读数据。在并发编程中,因为final变量不能再赋值,有利于减少额外的同步开销。

  3. ***final修饰变量指的是:这个变量被初始化后便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可变,即不能再指向其他的对象。如果final修饰的变量是对象类型,那么不可更改指的是该变量不可以再指向别的对象,但是对象的值时可以更改的,***比如下面代码。

//对象的值可以被修改
final List<String> strList = new ArrayList<>();
strList.add("hello");
strList.add("world");
 * 错误,调用方法的时候已经对x进行赋值,不能再对其进行++操作。
 */
public class Something { 
	public int addOne(final int x) { 
		return ++x; 
	}  
} 
/*
 * 正确,因为final修饰的类,但++的却是其对象,说明类属性改变,类不一定跟着改变
 */
public class Something { 
	public static void main(String[] args) { 
		Other o = new Other(); 
		new Something().addOne(o); 
	} 
	public void addOne(final Other o) { 
		o.i++; 
	}  
} 
class Other { 
	public int i;
} 

synchronized关键字最主要有以下3种应用方式

修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁

修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁

修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

final 可修饰 类、变量、方法

修饰类,不可被继承,比如String类
修饰变量,不可被改变,必须给定初值
修饰方法,不可被重写

static 可修饰 类、变量、方法

修饰内部类,不需要外部类实例,当做普通类使用
修饰变量,通过类名直接调用
修饰方法,通过类名直接调用

synchronized 代码块、方法,看具体代码位置,来实现代码的同步

修饰静态方法, 锁定Class对象
修饰普通方法, 锁定Object实例

@guosen ### synchronized 不能解决重排序问题吧,
如果 synchronized可以解决的话,单例的时候就不用volatile关键字了

@guosen ### synchronized 不能解决重排序问题吧, 如果 synchronized可以解决的话,单例的时候就不用volatile关键字了

synchronized 保证的单线程下的as-if-serial语义,所以保证的是有序性 并不能解决重排序问题

@guosen ### synchronized 不能解决重排序问题吧, 如果 synchronized可以解决的话,单例的时候就不用volatile关键字了

volatile保证的是可见性,不是有序性

之前面字节,有被问到synchronized的底层实现…