JAVA复建篇-01
1、基本常识
**java特点:**高性能,多线程,可移植,解释性语言,面型对象,安全
java特点:
封装:
不允许外部信息直接访问程序,而是通过该类方法实现对隐藏信息的操作和访问
//需要修改属性访问权限为private,创建对应属性的get和set方法,get和set方法内要有属性控制语句
public class student{
private float score;
public void setScore(float score){
this.score=score
}
public flaot getScore(){
return this.score
}
}
继承:
类与类之间允许继承父类的属性和方法的同时进行重载,从属关系,一个子类只能有一个父类
如狗类属于动物父类,人类属于哺乳动物父类,小明类属于人类
final修饰的方法可以被子类继承但是不能重写
//父类:动物类
public class Animal{
public int age;
public String name;
public void eat(){
System.out.println("动物具有吃东西的本领!");
}
}
//子类:狗类
public class Dog extends Animal {
}
多态:
对象的多种类型,存在引用多态和方法多态,继承是多态实现的前提
同一个行为具有多种不同表现形式或形态的能力(同一个对象产生的实例在不同事件下产生不同结果)
**存在三要数:**继承、重写、父类引用指向子类
使用方法多态时,先检查父类是否有该方法,父类没有就报错,有才调用子类方法
父类声明public的方法在子类中要么声明protected要么public,不能降为private,父类中声明private的方法子类不能继承
//引用多态,
//父亲类可以引用(创建对象)指向本类的对象,也可以指向子类的对象,前提是继承关系
//父类如果引用子类创建,则父类不允许调用子类独有的方法
public class Anaimal{
public int age;
public String name;
public void eat(){
System.out.println("eating");
}
}
public class dog extends Anaimal{
}
public static void main(String[] args) {
dog dog1 =new dog();
dog1.eat();
Anaimal a1 =new Anaimal();
Anaimal a2 = new dog();
}
//方法多态
//创建父类对象时,调用方法为父类方法
//创建子类对象时,可以调用继承自父类方法或者调用子类重写的方法
//使用方法多态时,先检查父类是否有该方法,父类没有就报错,有才调用子类方法//
1 //父类:动物类
2 public class Animal{
3 public int age;
4 public String name;
5 public void eat(){
6 System.out.println("动物具有吃东西的本领!");
7 }
8 }
9 //子类:狗类
10 public class Dog extends Animal {
11 public void eat(){
12 System.out.println("狗是吃肉的。");
13 }
14 }
15 //测试类
16 public class Test{
17 public static void main(String[] args) {
18 //父类的引用可以指向本类的对象
19 Animal ani1 = new Animal();
20 //父类的引用可以指向子类的对象
21 Animal ani2 = new Dog();
22 //输出动物具有吃的本领
23 ani1.eat();
24 //输出狗是吃肉的
25 ani2.eat();
26 }
27 }
1.1重载与重写
**重载:**依据参数数量、类型和传入顺序不同,方便JVM选择执行哪个函数
**重写:**在子类继承父类拥有方法后
- 子类可以根据需要对父类继承过来的方法进行重写
- 重写方法和被重写方法必须有相同的方法名称,参数列表和返回类型
- 重写方法不能使用比被重写方法更加严格的访问权限
- 构造方法不能重写。声明final和static的不能重写,但是static的可以再次声明
- 子类重写父类方法时不能再此降低访问权限(public的父类方法,子类不能声明低于public的方法)
- final修饰的方法可以被子类继承但是不能重写
//重载案例
public class myclass{
public void print(String name){
System.out.println("name"+name);
}
public coid print(String name,int age){
System.out.println("name:"+name+" age:"+age )
}
}
//
import myclass
public class mytest(){
public static void main(String[] args){
myclass my = new myclass();
my.print("网三");
my.print("里斯",20);
}
}
//重写
class Animal(){
public void move(){
System.out.println("animal");
}
}
class dog extends Animal(){
public void move(){
super.move();//重写方法要用super声明一下父类同名方法
System.out.println("dog");
}
}
public class test{
public static void main(String args[]){
Animal b = new Dog(); // Dog 对象
b.move(); //执行 Dog类的方法
}
}
1.2、虚函数
**c++定义:**某个类声明为virtual同时在一个或者多个派生类中被重新定义的成员函数。
虚函数主要是为了实现多态性,java类对象里普通成员函数就是虚函数
1.3、抽象类
一个类中没有足够信息来描绘一个具体对象就是一个抽象类
特点
-
抽象类不能直接实例化对象,必须继承后才能使用
-
父类时抽象类,可以包括继承子类的同名方法,但是不能使用
-
抽象类是一种继承关系,一个类只能继承一个抽象类,一个类却可以实现多个窗口
-
含有抽象方法的一定是抽象类
-
继承抽象类的子类必须重写父类方法,除非该子类为抽象类
-
构造方法不能声明为抽象方法
-
抽象类内允许存在实现方法的方法体,可以存在静态代码块或静态方法
public abstract class Employee{ private String name; private String address; private int number; public abstract double computePay(); }
-
抽象类允许使用添加属性的get和set方法和其他方法
//抽象方法employee
public abstract class Employee{
private String name;
private String address;
private int number;
public Employee(String name,String address,int number){
this.name=name;
this.address=address;
this.number=number;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public int getNumber() {
return number;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public void setNumber(int number) {
this.number = number;
}
}
//继承抽象方法的HR类
public class HR extends Employee{
private double salary;
public Salary(String name, String address, int number, double salary){
super(name, address, number);
setSalary(salary);
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
if(salary>=0.0){
this.salary = salary;
}
}
}
1.4、封装
抽象性函数式接口实现细节的部分封装,封装为接口。访问封装代码必须通过严格的接口控制
特点
- 良好的封装减少耦合
- 类内部结构可以自由修改‘
- 可以对成员变量进行更精确控制
- 隐藏信息实现细节
封装执行操作
- 对属性的可见权限修改(public修改为private等),但是提供访问方法(getter和setter)属于封装
//私有属性可以通过方法访问getset
public class Employee{
private String name;
private String address;
private int number;
public Employee(String name,String address,int number){
this.name=name;
this.address=address;
this.number=number;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public int getNumber() {
return number;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public void setNumber(int number) {
this.number = number;
}
}
1.5、接口
接口是抽象方法的集合,通过interface来进行声明。
特点
-
接口无法实例化但是可以被实现
-
接口包含属性和需要实现的方法名称
-
实现接口的类必须要实现该接口的所有方法,否则就必须声明抽象类
-
接口没有构造方法,内部所有方法必须为抽象方法(public abstract),接口不包含成员变量(static和final除外)
-
接口支持多继承,一个类可以实现多个接口
-
1.8后允许在接口里实现方法,允许声明静态方法(需要default修饰)’
-
接口内成员变量只能是public static final类型,默认是全局常量不能修改内容
package com.demo.jkl; public interface Vech { public static final int k =10; default void print(){ System.out.println("ssa"); } static void blowhorn(){ System.out.println("ss"); } }
package com.demo.jkl; public interface Vech2 { default void print(){ System.out.println("我是一辆四轮车!"); } }
package com.demo.main; import com.demo.jkl.Vech; import com.demo.jkl.Vech2; public class ReLearn01 implements Vech,Vech2 { public void print(){ Vech.blowhorn(); Vech.super.print(); Vech2.super.print(); } public void blowhorn(){ System.out.print("ReLearn01:blowhorn"); } public static void main(String[] args) { System.out.println("jjjjjk"); ReLearn01 vs= new ReLearn01(); vs.print(); vs.blowhorn(); } }
1.6、枚举
枚举表示一组特殊常量,使用enum定义,常量之间用逗号隔开。
枚举是一个特殊的类,表示一组常量,如一年12个月,一年四季度,颜色有多少中
特点
-
枚举是全局的,所以在类内外部都可以定义
-
循环可以迭代枚举元素
enum Coclor{ RED,BLUE,ORANGE,APPLE; } public class Test{ public static void main(String[] args){ Color[] color=Color.values(); for(Color col: color){ System.out.println(col+"at index"+col.ordinal()); //col.ordinal()返回索引 } } }
enum Color{
RED,GREEEN,ORANGE;
}
public class Test
{
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
}
1.7、详解JVM机制
JVM运行逻辑的自我理解
.java会先编译为字节码的.class文件,然后class文件会被类加载器子系统加载进内存,经过连接步骤时交由jvm运行数据区处理变量等信息,然后再交给执行引擎读取字节流,在通过解释后再编译去执行,从而完成初始化。
在执行引擎里,class字节流会经过过解析再编译的处理,这个过程可能会用到本地库接口调用c或者c++代码,pc毕竟是软硬件结合,java若是操作硬件还是c和c++好用
JVM的运行数据区
JVM划分程序计数器、虚拟机栈、本地方法栈、堆区、方法区和运行常量池以及直接内存区域。
-
程序计数器:线程私有,为当前所执行的字节码行号指示器,JVM中唯一没有内存溢出异常的OOM的区域。
目的为保存线程的执行状态,方便cpu读取回复线程状态,线程的上下文切换运行的需要程序计数器辅助
-
虚拟机栈,线程私有,生命周期与线程相同。描述方法执行的内存模块,每一个方法从调用到执行完成在虚拟机栈描述都是用栈帧的出入栈表示。
先假设有一个线程依次运行多个方法,且方法都在运行中(防止出虚拟机栈),则如图所示
注意JVM的执行引擎虽然是按照栈的方式执行,但是该栈不以虚拟机栈为运行栈,而是以图中的栈帧存储的操作数栈为栈,来保证逻辑上连续执行
虚拟机栈中栈帧详解
-
方法出口:方法执行时有两种退出情况,正常退出(return,areturn等方法结束关键字)和异常退出,且一定会返回方法被调用的位置。该位置信息用于执行错误处理、执行下一条指令或者压入上层调用栈帧
-
动态连接:每个栈帧里定会包含一个在常量池中对当前方法的应用,这个引用就是动态连接
-
局部变量表:存放方法形参与方法局部变量区域。其中局部变量必须显示初始化,非静态方法表中索引0位置上存的是方法所属对象的实例引用
-
本地方法栈,与虚拟机栈类似,但是本地方法栈为虚拟机本地方法服务,不操作字节码,只操纵native等级的本地方法,有SOE过栈异常和OOM过内存异常,用于执行c或者C++库内代码
-
java堆,区域共享,在jvm初始化时创建,java堆中保存着具体的java对象实例,几乎所有实例都在这里,存储内容必须保证逻辑上连续。
鉴于实例的生命周期短,堆区是垃圾回收机制性价比最高的地带。
-
方法区,也是区域共享地带,保存类信息、变量、静态变量和即时编译器编译后的代码数据。jvm规范里作为java堆得一部分存在,但是还单独划分non-heap,存储内容必须保持逻辑上连续
-
运行时常量池,方法区的一部分,保存编译期生成的各种符号引用。
该常量池创建是为了节约系统资源提高性能而创建,毕竟是常量没必要参考变量一样用完删除。
-
直接内存,系统内存,不指定大小默认与堆区一致
1.8、JVM垃圾回收机制
垃圾收集器一般作用于JVM的数据区的堆区。方法区也有回收机制,但是判定条件十分严苛
在JVM中堆区基本上算是占据内存最大的区域,堆区存储的对象的实例,被方法调用的实例一般都会在方法结束后失去作用,所以大部分垃圾收集器回收内存时也就作用于堆区回收对象实例。
垃圾回收器眼中的JVM堆区占据内存
堆区内存=新生代内存(1/3)+老年代内存(2/3)
新生代内存=Eden(0.8)+FromSurvivor(0.1)+ToSurvivor(0.1)
分新生/老年代的收集原理
- 首先时间短的或者刚出现的实例都在新生代分配内存,存活时间长的实例会从新生代内存区域转向老年代区域长期保持内存。
- 新生代的垃圾收集机制中存活的对象(存活一次年龄+1),会先从Eden来到FromSurvivor区域,待垃圾回收完后再进入Eden区域
- 新生代的FromSurvivor永远固定存在,实际大小也一定为10%,一定会被浪费(无论是否存储实例,一定10%属于FromSurvivor)
- 新生代内存优先在Eden区分配,一般Tosurvivor会被Eden占据,所以Eden实际内存会占据新生代的90%,垃圾回收释放的内存基本都是Eden的内存。
- 新生代的ToSurvivor和FromSurvivor可以相互切换,实际上的新生代会将两份10%空间做标记s0和s1。第一次回收时S0可以是FromSurvivor,第二次回收时S1也可以是FromSurvivor,交替存在。
- 长期存活的对象实例会变成老年代,JVM在每次进行垃圾回收时都会对存活对象的年龄加1,默认挺过15次垃圾回收也就是15岁时的对象进入老年代,这个年龄可以通过参数设定。
- 长字符串、元素多的数组、大对象的实例在进入Eden是经不起来回复制,也会占据大量内存,严重影响性能,所以这种最后直接设置其进入老年代
- 为了更好适应使用,在survivor空间中相同年龄的对象占据内存若是大于等于所有对象内存的一半,这些对象自动进入老年代
1.9、线程与进程,并发与并行
线程与进程
以电脑为例,打开qq软件,任务管理器跳出一个qq进程;打开百度云软件,任务管理器多了百度云进程。
然后在qq进程里,我跟一个人视频聊天,则打开一个qq的线程;我又通过qq打开小程序,则qq又多了个线程。
进程: 是计算机程序上关于某种数据集合的运行活动,是操作系统进行资源分配基本调度单位,可以叫做程序在系统上的实体。
线程: 为程序内部自我执行的操作最小单元,每个线程视为程序中单一的顺序控制流程。作为系统在进程可以操作的最小调度单位存在,单个程序运行多个线程完成不同工作成为多线程。
并行与并发
并行: 多个线程同时执行
并发: 假设在只有一个线程能运行情况下,多个线程争抢可以运行的机会