热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:关于Abstract,static,final的理解

Abstract,static,final理解一.Abstract

Abstract,static,final理解

一 . Abstract 抽象


1> 修饰类



  • 一个类被Abstract修饰之后,就不能new对象了,修饰父类


  • 被Abstract修饰的说明是一个不是一个具体的类型,是一个类别,是一个父类,不应该被具体化

  • 说明这个类不完整,不够具体,抽象类无法独立存在

  • 为子类输出共性


作用:
1> 可以被子类继承,提供共性属性和方法
2> 可声明为引用,强制使用多态
3> 抽象父类可以是子类的组成部分,依附于子类对象的存在
4> 由父类共性+子类独有组成完整的子类对象
5> 抽象类也是有构造方法的,可以由子类来调用,构建子类对象时调用父类构造方法
6> 和普通类的区别,就是不能new,其他和普通的类都一样

2> 修饰方法



  • 抽象方法:只有声明,没有实现,不够完整


  • 方法的声明时必要的,可是发放的实现是多余的,因为父类的方法的实现是无法满足子类的需求的,最后子类都会进行重写

  • 含有抽象方法的类必须是个抽象类

  • 抽象类中不一定有抽象方法

  • 子类必须重写父类的所有的抽象方法


//如果父类是个抽象
//那么子类必须重写父类的所有的抽象方法
//抽象类中不一定有抽象方法
abstract class Animal{//含有不完整的方法,那么这个类也是不完整的
String bread;
int age; public Animal(){
System.out.println("这是抽象类的无参构造函数..");
} //这是一个抽象方法
//含有抽象方法的类必须是个抽象类
public abstract void eat();//只有声明,没有实现,意为不完整 //还可以拥有普通的方法
public void slep(){};
}
//一个抽象类的子类
class Dog extends Animal{ //必须重写父类所有的抽象方法
public void eat(){

}}
//子类不想实现父类的抽象方法
//那么这个类也必须是个抽象类
//同时继承父类所有的未实现的抽象方法
abstract class Cat extends Animal{
}

二 . static 静态

类加载时.在方法区中,会存放一个有MyClass对象的类信息,MyClass.class


  • 普通的实例变量是在创建对象的时候在内存中创建对象


  • 静态方法是在类加载时就在内存中创建对象


  • 静态方法允许直接访问静态成员


  • 静态方法不能直接访问非静态成员


  • 静态方法中不允许使用this和super关键字


  • 静态方法可以继承,不能重写,没有多态


    • 动态方法要到运行时才是可以明确执行的是哪个,因为不能确定是否有子类将他重写覆盖了

    • 静态方法不用到运行时,编译时就会知道了.运行时不可变

    java中方法的调用分为两种

    ? 1> 静态分派: 静态方法中,允许参数列表不同的重名方法,指静态方法之间的重载

    ? 2> 动态分派: 在具有继承关系的情况下,调用实例方法时,自低向上(先查子类,再找父类,一直向上查找)查找可 用的方法版本,指实例方法的覆盖

    jvm方法调用的指令:

    ? 1> invokespacial 调用私有方法和构造方法

    ? 2> invokeinteface 调用接口方法

    ? 3> invokestatic 调用静态方法

    ? 4> invokevirtual 调用虚方法(父类定义的,日后被子类覆盖的方法)

    ? 5> invokedynamic 调用动态链接方法

    public class TestStatic{
    public static void main(String[] args){
    A.staticMethod();
    B.staticMethod();//继承了父类的静态方法,但是不能重写,所以不存在多态
    A a = new B();
    //也是可以掉调用的,即使在子类中也有一个同样的静态方法
    //下面的方法调用的依然是父类中的静态方法
    //因为静态方法不能被覆盖
    a.staticMethod();
    }
    }
    class A{
    static int find;
    public static void staticMethod(){
    System.out.println("----" + find);
    }
    }
    class B extends A{
    //假如B中也存在一个,也是不行的,不能覆盖
    public static void staticMethod(){
    System.out.println("----" + find);
    }
    }



1> 静态属性(类属性)



  • 静态成员是全类所有对象共享的成员


  • 在全类中只有一份,不因创建多个对象而产生多份


  • 不必创建对象,可以直接通过类名访问



a .普通的属性

public class TestStatic{
public static void main(String[] args){
MyClass mc1 = new MyClass();
m1.a = 10;

//每个对象都拥有自己单独的a
//每个对象都在堆中用一个自己的a空间,指向栈中的mc2引用
MyClass mc2 = new MyClass();
m2.a = 20;

System.out.println(m1.a + "--" + m2.a);//输出结果: 10 -- 20

}
}
class MyClass{
//每个对象都持有一例
int a; //实例属性
}

b.静态属性

public class TestStatic{
public static void main(String[] args){

//m1.b和m2.b访问的都是方法区中的b,是同一个
//每个类的实例都是使用的这一个b
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();

m1.a = 10;
m2.a = 20;

m1.b = 100;
m2.b = 202;//覆盖了前面的m1赋值的100//自动转换 m2.b --> MyClass.b //不用通过对象名访问静态属性
//直接使用类名访问
MyClass.b = 200;

System.out.println(m1.a + "--" + m2.a);//输出结果: 10 -- 20
System.out.println(m1.b + "--" + m2.b);//输出结果: 200 -- 200
}
}
class MyClass{ //实例属性
int a; //在这个类加载的时候,这个static属性就放到方法区了 //整个类的共享的.只有单独的一份
static int b; //静态属性
}

2> 静态方法

class Student{ //静态方法
//类的所有对象公用
public static void method(){

}
public void fan(){
//同一个类的其他方法使用本类的静态方法,直接使用方法名
method();
}}
class Test{
public static void main(String[] args){
//类外使用静态方法
//类名.方法名
Student.method();
}
}

3> static高级应用


1-类加载


  • JVM 首次使用某个类的时候,是需要通过CLASSPATH查找该需要使用类的.class文件


  • 将.class文件中对类的描述信息加载到内存中,进行保存(比如:包名,类名,属性,方法,构造方法等信息)


  • 加载的时机

    • 创建对象

    • 创建子类对象

    • 访问静态属性

    • 调用静态方法

    • Class.forName("全限定名") :(主动加载一个类,但是不接收返回值,只是加载到内存中,目前并不使用)


class TestClassLoaded{
public static void main(String[] args){
new Super();//首次用到,创建了一个类的对象,就需要加载这个类

Super.sMethod();//或者这个类中有静态方法,那么在首次调用这个静态方法的时候,也会加载这个类
Super.sname;//同上

Sub.sMethod();//调用父类的静态方法,首次使用也会加载super类,

}}
class Super{ String name; static String sname;//静态属性 //静态方法
public static void sMethod(
{

}
}

class Sub extends Super{}

2-静态代码块


  • 静态代码块是由类加载触发的(仅一次)

  • 可为静态属性赋值,或者必要的初始行为

  • 首先加载执行静态属性和静态代码块

  • 再来加载普通属性和动态代码块和构造方法

public class Test{
public static void main(String[] args){

//静态代码块是由类加载触发的

new MyClass;

System.out.print(MyClass.sname);//这两个都会执行静态代码块

}
}
class MyClass{

//静态属性
static int sname = 88; int name = 99; //静态代码块
static{
System.out.print("这诗集静态代码块中得到输出");

//使用了静态的属性
//执行静态代码块和静态属性的时候,根据书写顺序加载
//如这里使用了sname静态属性,那么这个属性必须定义到静态代码块前面
System.out.print(sname);
} MyClass{
System.out.print("类中音译的属性值为: " + name);
System.out.print("这是构造方法中得到输出");
} public void m1(){
int a = 10;
}
}

3- 各个模块之间的执行顺序

package com.huqi.demo1;
public class TestLoadSort{
public static void main(String[] args) throws Exception{

//new Super();
new Sub();//创建一个子类的对象,查看加载各个属性和代码块的顺序

//主动加载一个类,只执行静态代码的部分
Class.forName("com.huqi.demo1.Sub");//里面的必须带包名
/*
如果只执行这一行代码,则会输出下面的语句,这个是类级别的,从这里下面的代码都是对象级别的
这是父类的静态方法---
这是父类的静态代码块---
这是子类的静态方法---
是子类的静态代码块---
*/

}
}
class Super{
static String staticField = "这是父类的静态方法---"; static{
System.out.println(staticField);
System.out.println("这是父类的静态代码块---");
} String instanceField = "这是父类的成员属性---"; {
System.out.println(instanceField);
System.out.println("这是父类的动态代码块---");
} public Super(){
System.out.println("这是父类的构造方法---");
}}
class Sub extends Super{
static String staticField2 = "这是子类的静态方法---"; static{
System.out.println(staticField2);
System.out.println("这是子类的静态代码块---");
} String instanceField2 = "这是子类的成员属性---"; {
System.out.println(instanceField2);
System.out.println("这是子类的动态代码块---");
} public Sub(){
System.out.println("这是子类的构造方法---");
}
}

当new Sub时的结果
这是父类的静态方法---
这是父类的静态代码块---
这是子类的静态方法---
这是子类的静态代码块--- //从这里分割,前面的是类几级别的,类加载时运行,后面的都是创建对象时执行
这是父类的成员属性---
这是父类的动态代码块---
这是父类的构造方法---
这是子类的成员属性---
这是子类的动态代码块---
这是子类的构造方法---
当new Super时的结果:
这是父类的静态方法---
这是父类的静态代码块---
这是父类的成员属性---
这是父类的动态代码块---
这是父类的构造方法---

三.final



  • final修饰类: 此类不能被继承

  • final修饰方法: 此方法不能被覆盖

  • final修饰变量:此变量值不能被改变(无初始值.只允许赋值一次)

    • 局部变量 :显示初始化

    • 实例变量: 显示初始化,动态代码块,构造方法

    • 静态常量: 显示初始化,静态代码块

    • 基本数据类型常量:值不可改变

    • 应用数据类型常量: 地址不可变



1> final类



  • final修饰类: 此类不能被继承.

    • String.math.System均为final修饰的类,不能被继承


  • final修饰的方法不能被覆盖

public class testFinal{}
//final不能和abstract一起使用,是冲突的两个
final class Super{}
//发生错误,不能继承被final修饰的类
final Sub extends Super{}

2> final变量



  • final修饰变量,就变成了常量


  • 用final修饰的属性没有默认值

  • 只能赋一次值


public class testFinal{
main(){
//用final修饰的是常量
//先赋值再使用
final double PI = 3.1415;
}
}
//final不能和abstract一起使用,是冲突的两个
final class Super{ //没有默认值,必须要初始化
//在对象初始化完成之前完成初始化的操作
final int field = 10; final int FIELD; public Super(){
//对常量进行初始化
FIELD = 20;
} //静态常量
final static void STATIC_FIELD = 20; static{
//可以给STATIC_FIELD赋值
//STATIC_FIELD = 20;
}}

推荐阅读
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 本文介绍了解决java开源项目apache commons email简单使用报错的方法,包括使用正确的JAR包和正确的代码配置,以及相关参数的设置。详细介绍了如何使用apache commons email发送邮件。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • JVM:33 如何查看JVM的Full GC日志
    1.示例代码packagecom.webcode;publicclassDemo4{publicstaticvoidmain(String[]args){byte[]arr ... [详细]
author-avatar
kuqu00
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有