Java刘意第八天笔记

工具中使用静态:

在同一个类中,main方法只能访问静态方法。

【错误:无法从静态上下文中引用非静态,这样的错误一定是因为在main方法中调用了非静态方法。】

对非静态方法来说,只能通过对象(也就是其他类的对象)来调用非静态方法。

静态方法当然也可以,而且静态方法可以直接调用类名来访问。

下面考虑一个问题:

在工具类中,假如我不想被人创造对象,只想被人直接通过类名调用静态方法,该怎么办?

把类中的方法设定为静态之后,将构造方法私有,外界就不能创造对象了。

ArrayTool是工具的名字,printArray是其中的静态方法。

帮助文档的制作:

如果在工程中,你给别人的,别人给你的,都是无法阅读的class文件,而不是java,比如上文中的ArrayTool,就相当于,我给了你一个笔记本,你连开机都开不开,这个时候怎么办?你需要一个说明书。

第一步:

写一个工具类。

第二步:

对这个类加入文档注释【文档注释,就可以被解析为说明书】。

怎么加呢?加点什么呢?

文档注释的格式:

/**

*blablabla

*blablabla

*blablabla

/

@author:作者

@param:参数

@return:返回值

示例:

/**

  • 这是针对数组进行操作的工具类

  • @author 刘意

  • @version V.10

*/

public class ArrayTool {

//把构造方法私有,外界就不能在创建对象了

/**

* 这是私有构造

*/

privateArrayTool(){}



/**

* 这是遍历数组的方法,遍历后的格式是:[元素1, 元素2, 元素3, ...]

* @param arr 这是要被遍历的数组

*/

public staticvoid printArray(int[] arr) {

    System.out.print("[");

    for(intx=0; x<arr.length; x++) {

        if(x== arr.length-1) {

            System.out.println(arr[x]+"]");

        }else{

            System.out.print(arr[x]+",");

        }

    }

}



/**

* 这是获取数组中最大值的方法

* @param  arr 这是要获取最大值的数组

* @return 返回数组中的最大值

*/

public staticint getMax(int[] arr) {

    int max =arr[0];

   

    for(intx=1; x<arr.length; x++) {

        if(arr[x]> max) {

            max= arr[x];

        }

    }

   

    returnmax;

}



/**

* 获取指定元素在数组中第一次出现的索引,如果元素不存在,就返回-1

* @param arr 被查找的数组

* @param value要查找的元素

* @return 返回元素在数组中的索引,如果不存在,返回-1

*/

public staticint getIndex(int[] arr,int value) {

    int index= -1;

   

    for(intx=0; x<arr.length; x++) {

        if(arr[x]== value) {

            index= x;

            break;

        }

    }

   

    returnindex;

}

}

第三步:用javadoc工具解释文档注释

   格式:在cmd中输入:

javadoc –d 目录 –author –versionArrayTool.java

【目录如果是一个点,表示当前目录。目录可以写一个文件夹的路径,如果没有这个目录它会自动创建。找不到可以文档化的公共或保护的类:说明类的权限不够。只需要把要编译的类声明行的类名前加public】

解析后,用浏览器打开文档的index,就可以看到相当高端的解析后的class说明页面。

如何使用JDK的帮助文档:

显示(左上角)-索引-输入框,搜索自己需要的东西

举例:通过API学习MATH类。

代码块:

在java中,使用{}括起来的代码被称为代码块。但是根据其位置和声明的不同,可以分为局部代码块、构造代码块、静态代码块和同步代码块(最后一个先不讲。)

看下面的demo:

第二次输出x会报错,因为x的作用域已经结束了。

局部代码块:在方法中出现,限定变量生命周期,令其及早释放,节省内存空间。局部代码块是顺序执行的(块里块外都是)

什么意思呢?当我们创建了这样一个类,上下输出x和y的两个代码块,都会在创建code的对象时,先于构造方法而执行。

【如果没有给这个构造代码块,就会出现错误:需要标识符。动作不能直接放到类里】

(没找到符号,假装这里有一个向上的箭头)构造代码块:在类中的成员位置,用{}括起来的代码。每次调用构造方法执行前,都会先执行。可以把多个构造方法中的共同代码放到一起。

静态代码块:加一个static修饰。无论对象创建多少次,静态代码块只加载一次,而且先于构造代码块执行。一般用于对类进行初始化。

Quiz:静态代码块,构造代码块,构造方法的执行顺序?

静态代码块→构造代码块→构造方法

静态代码块只执行一次,其他两个每次都执行。

同样类型的代码块,按定义的先后执行。

一个应用:下面的代码,哪个先执行,哪个后执行?

class Student {

static {

    System.out.println("Student静态代码块");

}



{

    System.out.println("Student构造代码块");

}



publicStudent() {

    System.out.println("Student构造方法");

}

}

class StudentDemo {

static {

    System.out.println("林青霞都60了,我很伤心");

}



public staticvoid main(String[] args) {

    System.out.println("我是main方法");

   

    Student s1= new Student();

    Student s2= new Student();

}

}

执行结果:

继承:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。

如果类A继承于类B,那么A中就包含有B中的功能。

通过这样的方式,可以把一些不同的类中共有的功能集中到它们的父类上。有了继承以后,子类还可以定义一些新成员。

父类又称基类或超类,子类又称子类或派生类。

继承格式:

class 子类名 extends 父类名{}

继承的作用:

继承的特点:

1.只支持单继承,不支持多继承。即一个子类只能继承一个父类,不过一个父类可以被多个子类继承。(据说有些语言是支持多继承的)

2.但是,java中支持多层继承。

下面这样是可以的。

继承的注意事项:

  1. 子类只能继承父类所有非私有的成员(成员方法和成员变量)

【设想这样一种情况,父类中定义了一个公共方法,在这个方法中返回了私有的变量,那么子类是可以通过这个公共方法来获得私有变量的,但是不能直接继承父类的私有成员,这个和set/get方法是一个道理】

  1. 子类不能继承父类的构造方法,但是可以通过super关键字区访问父类构造方法。

  2. 不要为了部分功能而去继承。

上面这种写法为什么不好?因为我不要show1()啊。

什么情况下应该采用继承?假设法。

继承体现的是一种“is a”的关系。比如:
Person

   Student

   Teacher

Student is a Person

Teacher is a Person

如果有两个类A,B,只有它们符合A是B的一种(或者反过来),就可以用来继承。

那么如果子类和父类的变量/方法名重合了,会发生什么事?根据就近原则,会打印出离使用这个变量的语句最近的那一个值。也就是说查找范围是从小到大。

如果我想要的是成员范围类的变量呢?之前说过了,this关键字。

如果我想要父类成员范围的num(父类局部范围的num不能直接使用,因为方法之间是平级的,方法不能相互调用),就是用super关键字。

调用变量还是比较好理解的。但是继承中构造方法是什么关系呢?

子类中所有的构造方法默认都会访问父类的无参构造方法。

原因:子类可能要使用父类的数据。需要先使用父类的构造方法来初始化。子类的每一个构造方法的第一句语句默认都是:super()。

【针对上一句话补充一下:我自己做了一个测试,如果在子类的构造方法中没有写super()或者写了,都会调用父类的构造方法。但是如果子类在构造方法的第一句中显式地调用了父类地带参构造方法(super(”xxx”)),则会执行这个构造方法,不执行无参构造方法。】

如果父类没有无参构造方法(意思是显式地指定了并只指定了一个带参构造方法),直接用super()或者干脆什么都不写是一定会报错的(实际参数列表和形式参数列表长度不同),这个时候只能直接或间接地显式地调用父类的带参构造方法。

当然啦,我们都不希望出现这种情况,所以最好还是自己定义好所有无参构造方法。

Tips:this或者super在调用构造方法时,必须出现在第一条语句上。

一个类的初始化过程:

先对成员变量初始化(默认初始化/显示初始化/构造方法初始化)

什么意思呢?对上一个类来说,先初始化num(值为0),再赋值为10,最后执行构造方法的打印。

继承类的初始化过程:

对于同一个类:静态代码块>构造代码块>构造方法

对于继承的类,子类初始化之前先会进行父类的初始化。

看题的时候从main方法开始。

这里有个很精彩的例题,全文复制过来:

/*

看程序写结果:

    A:一个类的静态代码块,构造代码块,构造方法的执行流程

        静态代码块 > 构造代码块 > 构造方法

    B:静态的内容是随着类的加载而加载

        静态代码块的内容会优先执行

    C:子类初始化之前先会进行父类的初始化

   

结果是:

    静态代码块Fu

    静态代码块Zi

    构造代码块Fu

    构造方法Fu

    构造代码块Zi

    构造方法Zi

*/

class Fu {

static {

    System.out.println("静态代码块Fu");

}



{

    System.out.println("构造代码块Fu");

}



public Fu() {

    System.out.println("构造方法Fu");

}

}

class Zi extends Fu {

static {

    System.out.println("静态代码块Zi");

}



{

    System.out.println("构造代码块Zi");

}



public Zi() {

    System.out.println("构造方法Zi");

}

}

class ExtendsTest2 {

public staticvoid main(String[] args) {

    Zi z = newZi();

}

}

虽然子类中构造方法默认有一个super(),但是初始化的时候不是按照那个顺序进行的,而是按照分层初始化进行的,它仅仅表示先初始化父类,再初始化子类。

经过试验,这和构造方法有没有参数、调用哪个、怎么调用,都没有关系,结果不变。

继承中成员方法的关系:

子类中的方法和父类中的方法的声明一样时,会按照就近原则调用子类中的方法。

方法重写:子类中出现了和父类中方法声明一摸一样(方法名、参数列表、返回值类型)的方法。

【注意区分重写和重载:重载,是同一个类里,参数列表不同,与返回值无关】

当子类需要父类的功能,而功能主体子类有自己特有的内容时,可以重写父类中的方法。这样,既沿袭了父类的功能,又定义了子类特有的功能。

方法重写的注意事项:

  1. 父类的私有方法不能被重写。【你连访问都访问不到,就别想着覆盖了】

  2. 子类重写父类方法时,访问权限不能更低。【如果父类的方法是public,那子类的方法不能是private或者不声明】大于等于,最好一致。

  3. 父类的静态方法,子类也必须通过静态方法进行重写。

(这一点的具体解释到多态中再解释)静态和动态,父类和子类最好是一模一样。

子类重写父类方法时,最好声明一模一样,这样肯定不会出问题。

下面是两个面试题:

1:方法重写和方法重载的区别?方法重载能改变返回值类型吗?

方法重写:

在子类中,出现和父类中一模一样的方法声明的现象。

方法重载:

同一个类中,出现的方法名相同,参数列表不同的现象。

方法重载能改变返回值类型,因为它和返回值类型无关。

而方法重写肯定不可以。

Override:方法重写

Overload:方法重载

2:this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。

this:代表当前类的对象引用

super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员)

场景:

成员变量:

    this.成员变量

    super.成员变量

构造方法:

    this(...)

    super(...)

成员方法:

    this.成员方法

    super.成员方法

猜你喜欢

转载自blog.csdn.net/weixin_41130372/article/details/82769748