JAVA中的块、package和import 区别、javabean、权限修饰符、继承、重写(override)、super关键字

标签: 代码块  权限修饰符  继承  重写(override)  super关键字

块一共分为四种,分别是:普通程序块、构造代码块、静态代码块、同步代码块。代码块指的就是在代码中单独用花括号包裹起来的代码段,格式如下:

{
	Sysetm.out.println("我是代码块");
}

普通代码块

在类中出现的代码只要被花括号{}包裹起来的都叫做普通代码块,和普通的程序语句执行起来的顺序一模一样,普通代码块执行的循序就是谁先出现先执行谁。
但是即使一个类中出现不同的普通代码块,里面存储的方法和变量都有自己独立的作用域,但是都可以访问在自己所在花括号之外,所在类中的成员属性和方法。

public class Test{
    public static void main(String[] args) {
        int a = 1;
        {
            int b=2;
            int c=1;
            System.out.print(a);//可以访问普通代码块外的属性
            System.out.print(c);
        }
        {
            int c=3;
            System.out.print(c);
        }
       // System.out.print(b);这一句是不行的,b脱离作用域了
    }
}

构造代码块

直接在类中定义的而且没有加static的代码块被称为构造代码块,构造代码块在创建对象的时候被调用,每次创建对象的时候都会被调用,并且构造代码块的执行次序是优于构造函数的。
构造代码块在每次创建对象的时候被调用代码如下:

public class CodeBlock02{
    {
      //这里写在构造函数的前面,但是这并不是在构造函数之前执行的原因
      System.out.println("第一代码块");    
    }    
    public CodeBlock02(){
        System.out.println("构造方法");
    }       
    {
    //这里写在构造函数的后面,可以在结果上看到依旧是在构造函数之前执行的
     	System.out.println("第二构造块");
    }
    public static void main(String[] args){
	    new CodeBlock02();
	    new CodeBlock02();
	    // 在结果中可以看到,每次生成新对象的时候        
	    new CodeBlock02(); 
    }
}

运行结果如下:
在这里插入图片描述
当然这么看看不怎么直观,那么我们用一下反编译工具,看一下构造的代码块是执行在什么地方的。
在这里插入图片描述
我们和上面的代码一对比,第一代码块和第二构造块都是在构造方法里面先执行,随后在执行构造方法里面的内容。
所以从这里可以看出,构造代码块是先于构造方法先执行,但是不是单独执行构造代码块,而是把构造代码块拿到了构造方法里面执行。

静态代码块

在类中定义的有static关键词的代码块被称为静态代码块,静态类被用于初始化类,为类的属性初始化,对于一个类,其对应的静态代码只会执行一次,由于JVM在加载类时会先执行静态代码块,所以静态代码由于主方法执行(意思是,如果main函数定义在该类中,静态代码块也会先执行);
如果类中包含有多个静态代码块,那么将按照“先定义的代码先执行,后定义的代码后执行”;
静态代码块不能存在于任何的方法体内,因为本身是静态的,所以也只能访问对应类中的静态成员。

public class Code{
    {
      System.out.println("Code的构造代码块");
    } 
    static{
        System.out.println("Code的静态代码块");
        }      
    public Code(){
        System.out.println("Code的构造方法");
    }
}    
public class CodeBlock03{
     {
      System.out.println("CodeBlock03的构造代码块");    
     }
     static{
        System.out.println("CodeBlock03的静态代码块");
     }
     public CodeBlock03(){
     	System.out.println("CodeBlock03的构造方法");
     }
     public static void main(String[] args){
     System.out.println("CodeBlock03的主方法");
	     new Code();
	     new Code();
	     new CodeBlock03();
	     new CodeBlock03();
     }
}

运行结果如下:
在这里插入图片描述

同步代码块

这里的同步代码块指的是被Synchronized关键词修饰的代码块,在Java中,Synchronized关键词不仅仅可以用来修饰代码块,与此同时也可以用来修饰类、方法,是一种线程同步机制,被Synchronized关键词修饰的代码块会被加上内置锁。显然,因为是同步代码块,因此比被Synchronized关键词修饰的方法更加颗粒化(实际上因为本身同步是一种高开销的操作,因此我们应该尽量减少被同步的内容,很很多场景,我们没有必要去同步整个方法,而只需要同步部分代码即可,也就是使用同步代码块,因此在很多场景,自己更加推崇使用同步代码块),被Synchronized关键词修饰的代码块如下:

public class CodeBlock04 implements Runnable{
    public void method(){  
        synchronized(this){  
            System.out.print("这里是同步代码块");  
        }  
    } 
    public static void main(String[] args){
        CodeBlock04 a=new CodeBlock04();
        CodeBlock04 b=new CodeBlock04();
        a.method();
        b.method();
    }
}

当两个并发线程访问同一个对象object中的Synchronized(this)同步代码块时(不仅仅限于同一个代码块,只要是从属于同一个object),只有一个线程能够得以执行,另一个线程则处于阻塞态,只有在一个线程执行完该同步代码块之后,另外一个线程才能得以访问该同步代码块,但是对于非同步代码块,则完全不受影响。事实上,以上规则对于Java中的其他对象锁也是同样适用的。
  当然,要针对于同一个对象:

new Thread(a).start;
new Thread(a).start;
//两个从属于a的则会受到影响,而从属于b的则不会
new Thread(b).start;

最后提一点,对于Synchronized关键词修饰静态方法和对象,可以很容易推断的是,因为静态方法是属于类而不是属于对象的,因此使用Synchronized来修饰静态方法和静态对象的时候,类下的所有对象都会被锁定。

package、import 区别

  • package相当于给源文件标记一个名字,类似与C++里面的namespace。其最根本的作用是防止两个同名的类出现冲突,例如两个同名类文件XXX.class,为区别两个放在不同的包A和B下,使用的时候可以A.XXX或者B.XXX。
  • import的作用是导入一个类,类似与C++里面的#include,例如
import java.lang.*;//*作为我们的通配符来使用

上述语句语意为导入包java.lang下的所有类文件,也可以理解为告诉编译器,到java/lang/目录下寻找所有类文件。
还需要注意的是我们刚刚的那个“*”是通配符的含义,在我们使用的时候只是在预编译的时候需要较长的时间来查找到底是哪个包下面的方法,但是不会影响我们运行效率。

javabean

  1. 所有属性为private
  2. 提供默认构造方法
  3. 提供getter和setter
  4. 实现serializable接口

权限修饰符

我们之前在讲解知识点的时候都是拿pubic来演示的,那么今天说到了权限修饰符,那权限修饰符都有哪些呢?
一共分为:从最大权限到最小权限依次是:public、protected、包访问权限(default)和private,这是从大到小来看得,那么它们的权限区别到底是什么呢,一起来看一下下面的图就能清晰的了解了。
在这里插入图片描述

  • private: Java语言中访问权限最小的那个,被称为“私有的”。被其修饰的类、属性以及方法只能被本类中的对象访问,它的子类是不能访问,更不能跨包访问。
  • default:我们在写的时候可以不写这个关键字,系统默认是default,称为“默认的“。该权限下,只允许在同一个包中进行访问。
class Test{}//默认不写就是default,如果写了,编译就会报错
  • protected: 介于public 和 private 之间的一种访问权限修饰符,称为“受保护形”。被其修饰的类、属性以及方法只能被本类的方法及子类访问,即使子类在不同的包中也可以访问。
  • public: Java语言中访问权限最大的修饰符,称为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包(package)访问。

继承

概念

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
生活中的继承如图所示:
在这里插入图片描述
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是:is-a,是一个什么。父类更通用,子类更具体。
虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。
类的继承格式:

class 父类{}
class 子类 extends 父类{}

那么为什么要继承呢?我们看下面的代码我们创建两个动物类

/**
	动物1
*/
public class Penguin { 
    private String name; 
    private int id; 
    public Penguin(String myName, int  myid) { 
        name = myName; 
        id = myid; 
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是"         + id + "号" + name + "."); 
    } 
}
/**
	动物2
*/
public class Mouse { 
    private String name; 
    private int id; 
    public Mouse(String myName, int  myid) { 
        name = myName; 
        id = myid; 
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是"         + id + "号" + name + "."); 
    } 
}

我们看上面代码,有大量的代码重复比如吃饭、睡觉、编号都重复了,导致代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出错),所以要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类:

/**
	父类
*/
public class Animal { 
    private String name;  
    private int id; 
    public Animal(String myName, int myid) { 
        name = myName; 
        id = myid;
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是"         + id + "号" + name + "."); 
    } 
}

既然有了父类,那么动物1和动物2直接继承父类,使用父类的方法,就解决了我们代码重复且臃肿的画面,而且也方便后期的维护。

/**
	动物1
*/
public class Penguin extends Animal { 
    public Penguin(String myName, int myid) { 
        super(myName, myid); 
    } 
}
/**
	动物2
*/
public class Mouse extends Animal { 
    public Mouse(String myName, int myid) { 
        super(myName, myid); 
    } 
}

这样我们要后期维护时,只需要去父类中去修改方法,子类这边就不需要再去修改代码,直接调用方法就可以了。

继承的特性

  1. 子类继承父类 ,通过extends关键字实现
  2. 子类可以访问父类中的成员(属性 方法 public protected)
  3. 子类可以添加独有的成员
  4. 继承自父类的方法 不能满足子类需要 可以进行方法override(overload区别)
  5. 继承关系需要单继承 ,如果想要实现多个继承关系 进行传递 、利用接口
  6. 每一个类都有继承类 ,若不写extends关键字默认继承java.long.Object
  7. 在内存中在创建子类对象空间之前 ,默认创建父类的对象空间

重写(override)

重写(override)是什么?首先重写(override)是在继承基础之上才有的,当子类继承了父类之后才存在重写(override),当子类不满足父类方法里面的实现过程时,可以重写(override)父类里面的方法,代码如下:

public class Animal {
	public Animal(){}
	public void move(){
		System.out.println("父类中移动的方法");
	}
}
 
class Dog extends Animal {
  public Dog(){}
  public void move(){
	  System.out.println("子类重写父类的移动的方法");
  }
}

class Test{
	public static void main(String[] args) {
	    Dog a = new Dog();
	    a.move();
	}
}

运行结果如下:
在这里插入图片描述
这就是重写(override)父类中的方法,但是当父类中的方法被final修饰后就不能在被进行重写。
那么总结一下什么叫做重写(override):

  1. 类:子类和父类两个类一定产生继承关系
  2. 权限修饰符:子类的修饰符不能比父类的更严格,子类>=父类
  3. 特征修饰符:final不能被重写,static不存在重写,abstract必须重写
  4. 返回类型:如果是基本数据类型,子类必须要和父类的类型要一致;如果是引用数据类型,子类的返回类型不能比父类的大,子类<=父类
  5. 名字:子类的名字必须与父类的一致
  6. 参数:子类的参数必须与父类的一致
  7. 抛出异常:编译时子类抛出的异常类型小于等于父类个数或少于等于父类

还有一道最经典的题目叫做:重载和重写的区别?

  • 首先重载和重写都是针对方法的
  • 重写就是上面刚刚写的总结
  • 那重载是什么?我以前的文章有说过什么叫做重载,重载就是一个类中很多个方法,那怎么区分呢?方法的名字相同,参数列表不同,就是重载,那参数列表的不同体现在哪呢?体现在数据类型的类型、个数、顺序。这三点。如果还不清楚什么是重载的,请看一下我前几篇文章就清楚了。

super关键字

我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    super.eat();  // super 调用父类方法
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

运行结果如下:
在这里插入图片描述
还可以使用super关键字来调用父类中的构造方法

public class Animal {
	public Animal(){
		System.out.println("父类构造方法");
	}
}
 
class Dog extends Animal {
  public Dog(){
	  super();//调用父类的构造方法
	  System.out.println("子类中的构造方法");
  }
}

class Test{
	public static void main(String[] args) {
	    Dog a = new Dog();
	}
}

运行结果如下:
在这里插入图片描述

原文链接:加载失败,请重新获取