ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java学习 day07_extends

2021-06-16 09:05:20  阅读:175  来源: 互联网

标签:Java 静态 代码 day07 构造 extends Student new static


匿名对象

什么是匿名(anonymous)对象?

  • 没有名字的对象就是匿名对象

  • 这个名字是引用类型变量名,也就是引用的名字

  • 语法:就是创建一个对象,没有引用指向它

    new 类名();
    
  • 从实质上看,就是没有被栈上的引用指向,只孤零零的存在于堆上的对象就是匿名对象

匿名对象有啥用?

  • a,可以用匿名对象作为方法的返回值
  • b,作为对象调用方法
  • c,可作为方法的实参传递给方法
// 几种用途演示
public class Demo {
    public static void main(String[] args) {
        //创建一个匿名对象
        //new Student().method();
        //new Student().method();
        //new Student().method();
        //new Student().method();
        //new Student().method();
        //new Student().method();

        test(new Student());
    }

    public static Student test() {
        /*Student s = new Student();
        return s;*/
        //上述步骤二合一
        return new Student();
    }

    public static void test(Student s){
        s.method();
    }
}

class Student {
    public void method() {
        System.out.println("Student");
    }
}


# 代码块(block)

代码块概念

  • 在Java中,使用大括号”{}“括起来的代码被称为代码块,根据其位置和声明方式的不同,可以分为:
    • 局部代码块
    • 构造代码块
    • 静态代码块
    • 同步代码块(后边再说)
  • 总体而言,代码块在实际开发中,使用频率并不高,可替代性也很强
    • 但是由于其迷惑性极强,常年出没于各种面试题中
    • 这个东西很绕,需要深入理解

局部代码块(local)

什么是局部代码块?

  • 和局部变量位置相似,处在方法中局部位置的代码块,称之为局部代码块
  • 声明方式:{}
  • 位置:方法中的局部位置
  • 代码执行顺序:从上到下
  • 作用:限定局部变量的作用范围和生命周期,及早释放,提高内存利用率
  • 实际用途:并没有多大用,不要在代码中使用局部代码块,早起Java程序员用来提高内存利用效率

构造代码块(building)

什么是构造代码块

  • 和构造方法类似,处在类中成员位置的代码块,称之为构造代码块
  • 声明:{}
  • 位置:在类中成员位置
  • 作用:构造代码块会随着构造器的执行而执行,不管是哪个构造器,也就是new对象的时候

总结一下到目前为止,我们给成员变量赋值的方式:
分情况讨论
1,创建对象的时候
- a,默认初始化
- b,显式赋值
- c,构造器
- d,构造代码块
2,创建对象之后
- a,对象名点去赋值
- b,成员方法给成员变量赋值

  • new对象过程,构造代码块的执行顺序
    • 对象创建出来后,就把所有成员变量的值默认初始化,然后开始其余赋值操作
    • 如果构造器在第一行显式的调用了另一个构造器,那么程序先跳转到this构造器,但并不会执行
    • 而是
      • 按照类中定义代码块和成员变量的位置,从上到下执行代码块和成员变量自身的初始化语句
    • 继而执行该this构造器代码
    • 最后执行该构造器代码: 构造器一定是最后执行的
  • 需要注意的是:
    • 应该永远将构造代码块,放在成员变量的定义语句下面
      • 一方面,如果代码块初始化在上,成员变量声明在下,逻辑上会很奇怪
      • 另一方面,如果对象的创建依赖于代码块和成员变量的定义位置,很容易引发错误
    • 可以使用this关键字,但是意义不大

显式赋值和构造代码块,谁在代码书写顺序的上面,谁就先执行,反之在下面的要后执行


编译器在编译完代码后,实际上并不存在构造代码块的结构
编译器会智能的把显式赋值和构造代码块的代码,放入所有构造器的第一行,这么做:
1,为了保证变量都是先声明,再赋值
2,为了保证按照代码的书写顺序,从上到下执行显式赋值和构造代码块
- 写在书写顺序上面的就变成了显式赋值
- 写在书写顺序下面就跑到了构造器里面去了
3,为了保证构造代码块随着构造器的执行而执行(如果构造代码块中存在不是赋值语句的语句,会直接放入构造器的第一行)

package com.cskaoyan.building;

public class Building {
    public static void main(String[] args) {
        C c = new C(88);
    }
}

class C{
    {
        int a = 100;
    }
    int a = 99;
    public C(int a){
        this.a = a;
    }
}
// 在编译后的代码中,a=99被放在了构造函数中
  • 实践用途:
    • 构造器只是创建某一个对象时调用的,但构造代码块却是创建该类每个对象都会调用的
    • 因此,可以抽取出所有构造器都需要做的事情,放入构造代码块中

静态代码块

什么是静态代码块

  • 使用static关键字修饰的构造代码块,处在类中的成员位置,称之为静态代码块
  • 声明:static{}
  • 位置:类中成员位置
  • 作用:和静态成员一样,随着类加载而执行,一般用于给静态成员变量赋值,只执行一次
  • new对象过程,静态代码块、构造代码块、构造方法的执行顺序
    • 静态代码块
    • 构造代码块
    • 构造方法
  • 需要注意的是:
    • 静态代码块和静态成员一样,不能在里面调用非静态
    • 除非是静态成员变量需要很复杂的初始化代码,否则没太大必要使用,直接显式赋值就行
    • 静态代码块和静态成员变量的定义顺序,也会影响到静态成员变量的最终取值(谁在下面,谁后执行)
      • 所以应该永远将静态代码块放在静态成员变量的定义下面
    • 构造代码块可以给静态成员变量赋值,静态代码块却不能给普通成员代码块赋值
      • 若构造代码块和静态代码块同时给一个静态成员变量赋值
        • 它们在代码中的顺序,并不会对结果造成影响
      • 因为静态代码块总是先于构造代码块执行

一些实际的使用案例

  • 构造代码块使用场景:
    • 不想让对象共享一个属性(static),但是还需要对象的某个属性具有相同初始值。
    • 比如公司新来了一批员工,他们的初始薪资一样,但是后面会根据表现调薪
      • 这个时候如果用static,显然不合适,因为调薪是针对个人的
      • 使用普通的成员变量定义薪资,然后用构造代码块给变量赋值
  • 静态代码块的经典使用场景:
    • 复杂的静态变量初始化
    • JDBC的驱动加载(Java EE学)

一定会触发类加载的几种情况

  • 执行某个类的main方法,一定会进行类加载
  • 创建某个类的对象,一定会进行类加载
  • 访问某个类的静态成员,一定会进行类加载

牛刀小试

查看以下代码,请回答程序运行的结果

public class ExerciseBlock {
// 2.静态代码块在类加载时执行,输出第一个
    static {
        System.out.println("main方法静态代码块!");
    }
    {
        System.out.println("main方法构造代码块!");
    }
    // 1.程序的入口,但是要先去进行所在类的类加载
    public static void main(String[] args) {
    // 3.回来执行main方法,输出main方法开始执行!
        System.out.println("main方法开始执行!");
 
        Star s = new Star(8,"马化腾");
	//6.按照顺序,Star.name是刘亦菲
        System.out.println(Star.name);
    // 7. s.age就是传递的参数,也就是8
        System.out.println(s.age);
    }
}
class Star{
    {
        age = 18;
        Star.name = "杨超越";
        System.out.println("我喜欢杨超越");
    }
    // 4.main方法创建了star对象,先处理static修饰的,static代码块输出我喜欢杨幂
    static String name = "王菲";
    int age = 28;
    static {
        name = "杨幂";
        System.out.println("我喜欢杨幂");
    }
// 5.创建对象使用这个构造器,在里面调用下面的构造器,不过还是先执行构造代码块里的东西
// 所以输出我喜欢杨超越,age和age,name
    public Star(int age,String name) {
        this(age);
        System.out.println("age,name:构造器!");
        Star.name = name;
        Star.name = "刘亦菲";
    }
    public Star(int age) {
        System.out.println("age:构造器!");
        this.age = age;
    }
    public Star() {
    }
}
  • 程序的打印结果应该什么呢?
    在这里插入图片描述


package和import关键字

package和import两个关键字涉及到了一个Java文件中的包的操作

package

作用?

  • 在Java源文件的第一行,使用package关键字声明

    • 声明该Java源文件中,所定义的所有类,都属于同一个包
      • 一个Java源文件,只能有一个public修饰的类
    • package关键字后,跟上当前类的包名,表示所处的包
  • 语法

    • package 包名;
      
  • 注意

    • 包名的书写,用逗号隔开
    • 语法上,该声明语句一定位于一个Java源文件的有效代码的第一行,否则会报错
      • 注释不算有效代码,你可以把package声明放在注释下面
      • 但是根据规范,不要这么做
      • 应该将package永远放在Java源文件真正意义的第一行
      • 3,如果一个class直接放在src目录根目录,它就无需包声明

全限定类名

什么是全限定类名?

  • 可以唯一确定一个类的,由包名加上类名组成的字符串
  • 不做任何操作的情况下,直接输出一个类的对象,会打印全限定类名
  • 例如:com.cskaoyan.oop.statickeyword.Star

import

引例

  • 在包名为onepackage的包中创建一个Student类
  • 在包名为anotherpackage的包中创建一个同名Student类
  • 在onepackage包下,写一个测试类Test
  • 在测试类Test中,创建anotherpackage包中Student类的对象

显然编译器会默认优先搜索同包下的,Student类,然后去创建它的对象

为了让编译器,去获取到不同包下的,Student类,必须由程序员显式的告诉编译器怎么去找到这个类

有两种解决方法

  • 在创建类的对象的语句中,不使用简单的类名,而是使用全限定类名

    • 不可能真的这么做,因为全限定类名太长了
  • 使用import关键字,声明要使用的类

    • 语法

      • import 全限定类名;
        
    • 语法上import关键字应该放在,package声明语句和类声明语句之间

      • 和package关键字一样,import声明应该永远紧跟在package声明之后(规范)

      • import声明提供了一种包的智能导入方式,语法为

        • import <包名>.*;
          
        • 包中的类将根据需要导入,避免使用多条import声明

        • 需要注意的是,如果本包中已存在同名类,就判定为不需要导包,.*就不会自动导包,只有在不导包就会报错的情况下,才会使用到智能导包

    • Java语言核心包java.lang包中的类将被隐式导入,可以直接使用其中的类

      • import java.lang.*;
        
      • 我们使用的String、Integer、System都属于这个包

  • 静态导入

    • 语法

      • import static 全限定类名.*;
        import static 全限定类名.静态成员;
        
    • 可以用来导入静态方法和静态成员变量

    • 以往我们调用不同包的静态成员,通过类名.成员名访问,如果静态导入,可以省略类名

    • 例如

      • import static java.lang.System.*;
        
      • 可以这样写输出语句

        out.println("Hello World!");
        
      • import static java.lang.Math.*;
        
      • 可以这样使用

        double pi = PI;
        double result = pow(2,3);
        
  • 实践开发中,static导入很少使用,了解认识即可


如果不同包下两个同名类,我都想使用咋办?

  • 真的存在这种需求,建议改名一个
  • 一个用全限定类名去使用

标签:Java,静态,代码,day07,构造,extends,Student,new,static
来源: https://blog.csdn.net/weixin_43385930/article/details/117918173

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有