java总结

静态方法与非静态方法的区别  

生命周期:

 

静态方法:与静态成员变量一样,属于类的本身,在类装载的时候被装载到内存,不自动进行摧毁,会一直存在内存中,直到JVM关闭.

 

非静态方法:又叫实例化方法,属于实例对象,实例化后才会分配内存,必须通过类的实例来引用。不会常驻内存,当实例对象被JVM回收之后,也跟着消失。

 

效率:

静态方法的使用效率比非静态方法效率高。

 

按照上面的概念,只要内存够用,都可以使用静态的。使用静态方法会带来什么问题呢。

静态方法:是共享代码段,静态变量是共享数据段。既然是”共享”就有并发的问题。

非静态方法:是针对确定的一个对象的,所以不会存在线程安全的问题.

静态方法和实例方法是一样的,在类型第一次被使用时加载。调用的速度基本上没有差别。

 

 

 

例如:

  1. 不需要生成对象的  经常频繁使用的  工具类里的(如SqlHelper)
  2. 个人理解在多个类中需要调用并且是与对象无关的方法可设为静态方法。
  3. 不需要生成对象的  经常频繁使用的  工具类里的(如SqlHelper)
  4. 适当地使用static方法本身并没有什么,当一个人从来不懂使用多态、接口设计时,很自然地会滥用static方法。
  5. 个人理解在多个类中需要调用并且是与对象无关的方法可设为静态方法,方便调用。
  6. 所有对象共有的方法
  7. 再不关系到任何于特定对象相关的操作  比如学生的年龄就是学生的相关。  修改学生的年龄就不适合用静态方法。  一般来说,如果你的方法里没有用到this关键字,  那就适合用静态方法
  8. 通常通用的类中一些常用的方法可以设计为静态类
  9. 只要是没有用到类的状态信息,只从参数获取信息的都可以为静态的
  10. 可以实现某些特殊的设计模式:如Singleton
  11. 由于没有this指针,可以把某些系统API的回调函数以静态函数的形式封装到类的内部
  12. 可以封装某些算法,比如数学函数,如ln,sin,tan等等,这些函数本就没必要属于任何一个对象,所以从类上调用感觉更好
  13. 总之,从OOA/OOD的角度考虑,一切不需要实例化就可以有确定行为方式的函数都应该设计成静态的
  14. 静态方法与非静态方法最明显的区别就是如果某个方法是公共静态的,那么可以直接通过类名.方法名的方法来调用,而公共实例方法则需要事先实例化对象,然后才能调用。

 

优势与弊端:

在一些系统中使用非常平凡的方法都使用静态方法可以提高系统性能。

本身不可升级,重写,这要看一个软件产品的目的是什么。

为了方便,不用实例化,但这样程序编译运行时就占用了系统资源。

 

静态的属性和方法在程序启动的时候,就全部装入内存的,而不管这些方法、属性以后有没有用到。及时是没有人在访问程序,这部分内存任然不会释放。还有就是,所有访问者看到的静态属性的数据几乎都是一样的,比如A用户设置了UserName这个属性,B用户访问的时候,得到UserName任然是A用户设置那个。这种特性,如果用在固定数据中,那不会太大问题。

 

 

 

 

 

方法区:method(方法区)又叫静态区,存放所有的①类(class),②静态变量(static变量),③静态方法,④常量和⑤成员方法(就是普通方法,由访问修饰符,返回值类型,类名和方法体组成)。

 

堆:

jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 

 

栈:

Java栈的区域很小,只有1M,特点是存取速度很快,所以在stack中存放的都是快速执行的任务,每个方法执行时都会创建一个栈帧(Stack Frame),描述的是java方法执行的内存模型,用于存储局部变量,操作数栈,方法出口,基本数据类型的数据,和对象的引用(reference)等,返回值,返回地址信息等。每个方法的调用都对应的出栈和入栈。

 

 

程序计数器(ProgramCounter)寄存器:

PC寄存器( PC register ):每个线程启动的时候,都会创建一个PC(Program Counter,程序计数器)寄存器。PC寄存器里保存有当前正在执行的JVM指令的地址,当字节码解释器工作时,通过改变这个计数器值来选取下一条需要执行的字节码指令,分支,循序,跳转,异常,循环,线程恢复等基础功能都需要依赖这个计数器来完成。

 

 运行时常量池:

是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

 

本地方法栈:

本地方法栈与Java虚拟机栈发挥的作用非常相似,它们之间的区别在于虚拟机栈为虚拟机执行java方法(也就是字节码文件)服务,而本地方法栈则为使用到Native方法服务。

 

 

 

静态代码块、非静态代码块 区别以及用途

第一步:我在root孙类定义main方法程序入口 孙类实例化了一个对象

第二步:首先会加载root父类的静态方法

第三步:然后加载root 子类的静态方法

第四步:然后加载root 孙类的静态方法

第四步:加载root父类的 普通代码块

第五步:加载root父类的构造代码块

第六步:加载root 子类的普通代码块

第七部:加载root子类的构造代码块

第八步:加载root孙类实例化对象

第九步:加载实例化对象 静态块

第十部:加载实例化对象 普通代码块

第十一部:root孙类的 普通代码块

第十二部:root 孙类的 构造代码块

 

注意:静态代码块只执行一次

 

 

局部变量和全局变量以及成员变量的区别

成员变量:

  1. 写在类声明的大括号中的变量,我们称之为成员变量(属性,实例变量)。
  2. 成员变量只能通过对象来访问
  3. 注意:成员变量不能离开类,离开类就不是成员变量 成员变量在定义的同时不能进行初始化。
  4. 存储:堆(当前对象对应的堆的存储空间中)
  5. 存储在堆中的数据,不能被自动释放,只能程序员手动释放

 

 

全局变量:

  1. 写在函数和大括号外部的变量,我们称之为全局变量
  2. 作用域:从定义的哪一行开始,一直到文件末尾。
  3. 全局变量可以先定义在初始化,也可以定义的同时初始化,有默认初始值
  4. 存储:静态区(方法区)
  5. 程序已启动就会分配存储空间,直到程序结束才会释放。

 

局部变量:

  1. 写在函数或者代码块中的变量,我们称之为局部变量
  2. 作用域:从定义的那一行开始,一只到遇到大括号或者return
  3. 局部变量可以先定义再初始化,也可以定义的同时初始化,没有默认初始值
  4. 存储:栈
  5. 存储在栈中的数据有一个特点,系统会自动给我们释放。随着方法的调用或者代码块的执行而存在,随着方法的调用完毕或者代码块的执行完毕而消失

 

 

Java中基本数据类型和引用数据类型的对比

特点:

   基本类型:不同的变量会分配不同的存储空间,并且存储空间中存储的是该变量的值。赋值操作传递的是变量的值。

引用数据类型:赋值是把原对象的引用传递给另外一个引用。对数组而言,当一个数据引用赋值给另外一个数组引用后。这两个引用指的是同一个数组,也就是指的同一块内存空间。

 

 

 

 

 

访问修饰符

Default:(及缺省,什么也不写):在同一包内可见,不使用任何修饰符.使用对象:类、接口、方法名、变量。

Private:在同一类可见,使用对象、变量、方法  不能修饰类(外部类)。

Publci:所有类可见。使用对象,类,接口、变量、方法。

Protected:对同一包内的类所有子类可见。使用对象、方法、构造方法。  注意:不能修饰类(外部类)。

 

重写与重载之间的区别

区别点 重载方法 重写方法

参数列表 必须修改 一定不能修改

返回类型 可以修改 一定不能修改

异常 可以修改 可以减少或删除,一定不能抛新的或

者更广的异常

访问 可以修改 一定不能做更严格的限制(可以降低 限制);

总结:

  方法的重写(Overriding)和重载(Overriding)是java多态性的不同表现,重写是父类与子类之间多态的一种表现,重载可以理解成多态的具体表现形式。

 

  1. 方法的重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为重载。
  2. 方法重写是在子类存在父类的方法名字相同,而且参数个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
  3. 方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

 

Java多态

  多态是同一个行为具有不同形式或形态的能力。

多态就是一个接口,使用不同的实例而操作不同操作.

 

方式一:重写:

这个内容已经在上一章节详细讲过,就不再阐述,详细可访问:Java 重写(Override)与重载(Overload)。

方式二:接口

1. 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。

 

2. java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。具体可以看 java接口 这一章节的内容。

 

方式三:抽象类和抽象方法

 

 

Java接口

 

Java的接口中到底起什么作用

  1. 从书中看到的是java 程序的接口中定义了常量及空方法,空的方法有什么用呢?还要在类中写方法体,还需要接口干什么。
  2. 一个程序中写了2个接口,并在同一个类中写方法体,这与多继承有什么关系.
  3. 包中那些已定义的接口,怎么知道那里面定义了什么方法。

解决思路:

java接口的用处主要体现下面几个方面:

  1. 通过接口可以实现不相关类的相同行为,而不需要了解对象所对应的类。
  2. 通过接口可以指明多个类需要实现的方法。
  3. 通过接口可以了解对象的交互界面,而不需要了解对象所对应的类

 

 

 

另一个思路:

类描述了一个实体,包括实体的状态,也包含实体可能发出的动作。

接口定义了一个实体可能发出的动作。但是只是定义了这些动作的原型,并没有实现,也没有任何的状态信息。

所以接口有点像一个规范、一个协议,是一个抽象的概念;而类则是实现了这个协议,满足了这个规范的具体实体,是一个具体的概念。

从程序角度,简单理解,接口就是函数声明,类就是函数实现,需要注意的是同一个声明可能有多种实现。

所以你的问题:

  1. 接口中定义类方法的原型,但是不能说空方法,因为空方法的意思是有实现体的,只不过实现体是空操作。实际上接口没有定义任何实现体。具体的实现体都是在实现接口的类中,接口只是定义了这些方法的调用方式。

你当然也可以不用接口,直接在类里面写方法,但是如果你的一组方法需要很多类里实现,把他们抽象出来,做成一个接口规范,不跟好么。。

  1. 一个类描述了一个实体,这个实体可能是一个复杂的对象,它的动作很多,如果把这些动作分类,用接口a定义其中的某一组动作,接口b定义其中另外一组动作,这样的结构,比较清楚。

这种方式具备了多继承的优点,避免了多继承的缺陷。实际上在历史上,接接口在很大程度上,是为了解决多继承带来的种种问题而设计出来的。

  1. 包中那些以定义的接口,怎么知道那里面定义了什么方法

接口里定义了方法的输入输出,这些都是协议,具体的实现都在每个类中。对于很多只需要抽象接口的地方,不需要知道具体的类是什么,只要这个类实现了这个接口就可以了。

 

 

Java 抽象类

接口和抽象类有什么区别

 

你选择使用接口和抽象类的依据是什么?

 

接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。

 

抽象类表示的是,这个对象是什么。接口表示的是,这个对象能干什么,比如,男人,女人,这两个类(如果是类的话....),他们的抽象类是人。说明,他们都是人。

 

人可以吃东西,狗也可以吃东西,你可以把”吃东西”定义成一个接口,然后让这写类去实现它。

 

所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口啊(吃饭接口,走路接口)。

 

第一点:接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类声明方法的存在而不去实现它的类.

 

第二点:接口可以多继承,抽象类不行

 

第三点:接口定义方法,不能实现,而抽象类可以实现部分方法。

 

第四点:接口中基本数据类型为static 而抽象类不是的。

 

当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口

 

抽象类的功能远远超过接口,但是,定义抽象类的代价高,因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类。在这个类中,你必须继承或编写出所有子类的所有共性。虽然接口在功能上回弱化许多,但是它只是针对一个动作描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度。

 

相同点:1.都不能被实例化

2.接口的实现类或抽象类的子类都实现了接口和抽象类中的方法才能实例化。

 

标记接口

Java中常用的三个标记接口分别是:RandomAccess,Cloneable、Serializable,在查看jdk源码时,我们经常发现这些接口的存在,它们不包含任何的方法,它们的作用就是当某各类实现这个接口的时候,我们就认为这个类拥有了接口标记的某种功能。

主要有两种目的:

建立一个公共的父接口:

正如一个接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口建立一组接口的父接口。Java虚拟机就知道该接口将要被用于一个事件的代理方案。

 

向一个类添加数据类型:

这种情况标记接口最初的目的,实现标记接口的类不要需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。

 

 

 

Java 封装

优点:1.良好的封装能够减少耦合

  1. 类内部结构可以自由修改。
  2. 可以对成员变量进行更精确的控制
  3. 隐藏信息,实现细节。

 

Java 包(package)

包的作用:

 

 

  1. 把功能相似或相关的类或接口组织在同一个包中,方便类查找和使用
  2. 如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字可以相同,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
  3. 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

 

 

 

Java 数据结构

Java 工具包提供强大的数据结构.在java中数据结构主要包括以下几种接口和类。

 

  1. 枚举(Enumeration)
  2. 位集合(BitSet)
  3. 向量(Vector)
  4. 栈(Stack)
  5. 字典(Dictionary)
  6. 哈希表(Hashtable)
  7. 属性(Properties)

 

 

枚举(Enumeration)

枚举(Enumeration)接口虽然它本身不属于数据接口,但它在其它数据结构的范围里应用很广,枚举(Enumeration)接口定义了一种数据结构中取回连续元素的方式。

 

例如,枚举定义了一个叫nextElement的方法,该方法用来得到一个包含多元素的数据结构的下一个元素。

 

 

 

位集合(BitSet)

位集合类实现了一组可以单独设置和清除的位或标志。

该类在处理一组布尔值的时候非常有用,你只需要给每个值赋值一”位”,然后对位进行适当的设置或清除,就可以对布尔值类型进行操作了。

 

向量(Vector)

向量(Vector)类和传统数组非常相似,但是vector的大小会根据需要动态的变化。

和数组一样,Vector对象的元素也能通过索引访问。

使用Vector类主要的好处就是在创建对象的时候不必给对象指定大小,它的大小会根据需要动态的变化。

 

栈(Stack)

栈实现了一个后进先出(LIFO)的数据结构.

你可以把栈理解为对象垂直分布的栈,当你添加一个新元素时,就将新元素放在其他元素的顶部。

当你从栈中取元素的时候,就从栈顶取一个元素。换句话说,最后进栈的元素最先被取出

 

属性(Properties)

Properties 继承于 Hashtable.Properties 类表示了一个持久的属性集.属性列表中每个键及其对应值都是一个字符串。

 

Properties 类被许多Java类使用。例如,在获取环境变量时它就作为System.getProperties()方法的返回值。

 

 

 

Java 集合框架

接口:是代表集合抽象数据类型.例如Collection、List、Set、Map等,之所以定义多个接口,是为了以不同的方式操作集合对象

 

实现(类):是集合接口的具体表现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。

 

算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称之为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。

 

 

 

 

Java 泛型

 Java泛型是JDK 5 中引入的一个新特性,泛型提供编译时类型安全监测机制,该机制运行程序员在编译时检测到非法类型。

泛型的本质是参数化类型,也就是说操作的数据类型被指定为一个参数。

 

<? extends T>和<? super T>的区别

<? extends T>表示该通配符所代表的类型是T类型的子类

<? super T>表示该通配符所代表的类型是T类型的父类

 

 

 

Java 序列化

Java提供了一种对象序列化机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。

将序列化对象写入文件之后,是可以从文件读取出来的,并且对它进行发序列化,也就是说,对象的类型信息。对象的数据,还有对象中的数据类型可以用来在内存中新建对象。

整个过程都是java虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化对象。

类ObjectInputStream和ObjectOutStream是高层次的数据流,它们包含反序列化和序列化对象的方法。ObjectOutStream类包含很多写方法来写各种数据类型

 

Java反射机制

反射机制

-指的是可以于运行时加载、探知、使用编译期间完全未知的类。

-程序在运行状态中,可以加载动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。

 

Class<?> c =Class.forName(“类名全路径”);

-加载完类之后,在堆内存中,就产生一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类结构信息。我们可以通过这个对象看到这个类的结构。这个对象就像一面镜子,透过这个镜子看到这个类的结构,所以,我们形象的称之为:反射。

 

实例:对象是表示或封装的数据,一个类被加载后,jvm会创建一个该类的Class对象,类的整个信息会放到指定的Class对象中。

这个Class对象就像一面镜子,通过这面镜子可以看到类的全部信息。

 

 

 

类加载全过程

类加载机制

-JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用的Java类型的过程.

 

-加载

-将class文件字节码内容加载到内存中,并将这些静态数据换成方法区中的运行时数据结构,在堆中生一个成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。    这个过程需要类加载器参与。

 

 

链接: 将Java类的二进制代码合并到JVM的运行状态之中的过程

 

验证:

-确保加载类信息符合JVM规范,没有安全方面的问题。

 

准备:

-正式为类变量(静态变量)分配内存并设置类变量初始值的阶段,这些内存都将方法区中进行分配。

 

解析:

-虚拟机常量池内的符号引用替换为直接引用的过程。

 

 

-初始化

1.初始化阶段是执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收集类中的所有变量的赋值动作和静态语句块(static块)中语句合并产生的。

2.当初始化一个类的时候,如果发现其父类还没有进行初始化、则需要先出发其父类的初始化

3.虚拟机保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步.

 

类的主动引用(一定会发生类的初始化)

 -new一个类的对象

 

 -调用类的静态成员(除了final常量)和静态方法

 

-使用java.lang.reflect包的方法对类进行发射调用

 

-当虚拟机启动,java Hello,则一定会初始化Hello类。说白了就是先启动main()方法所在的类。

 

-当初始化一个类,如果其父类没有初始化,则先会初始化他的父类。

 

类的被动引用(不会发生类的初始化)

- 当访问一个静态域时,只有真正声明这个域的类才会被初始化

通过子类引用父类的静态变量,不会导致子类初始化

 

-通过数组定义类引用,不会触发此类的初始化

 

-引用常量不会触发此类初始化(常量在编译阶段就存入常量池中了)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值