static 关键字
被static关键字修饰的方法一般被称为静态方法 没有被static关键字修饰的方法 一般称为非静态方法。同理 被static关键字修饰的成员变量 叫静态的成员变量 ,没有被static修饰的叫非静态成员变量。
(1)静态方法 :只能访问静态的成员变量 如果访问非静态成员变量 那么无法通过编译,无需创建对象,使用类名就可以直接调用。
(2)非静态方法:既能访问静态的成员变量,也能访问非静态的成员变量 只能通过创建对象的方式进行调用。
注意:静态的成员变量和静态的方法 无需创建对象通过类名进行访问。静态方法和静态成员变量 被整个程序共用 相当于共享。被static修饰的内容 在代码程序中会按照顺序进行加载, 如果主函数在下面,那么会优先加载静态成员变量和成员方法。
示例:
public class Person {
private String name;
private int age;
private String sex;
//静态函数块
static{
System.out.println("000");
}
private static Person p = new Person();
//构造函数无参
public Person() {
System.out.println("没有参数的构造方法");
}
//使用this关键字进程成员变量的赋值 -----初始化
//有参构造函数 两个参数
public Person(String name,int age){
this();
this.name = name;
this.age = age;
System.out.println("拥有两个参数的构造方法");
}
//有参构造函数 三个参数
public Person(String name,int age,String sex){
this(name,age);
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("拥有三个参数的构造方法");
}
//提供访问的方式 set设置 get获取方法
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
//主函数
public static void main(String[] args) {
Person p1 = new Person("张洒",30,"M");
}
}
练习:下面代码结果是什么?
public class StaticTest {
private static StaticTest st = new StaticTest();
private static int count1;
private static int count2 = 0;
public StaticTest() {
count1++;
count2++;
}
public static StaticTest getInstance(){
return st;
}
public static void main(String[] args) {
StaticTest st = StaticTest.getInstance();
System.out.println("count1:"+count1);
System.out.println("count2:"+count2);
}
}
//分析先是执行静态函数结果为count1=1,count2=1。后面进行构造函数此时count2=2;
//最终结果就是count1=1,count2=0
:结果:
count1:1
count2:0
继承
继承的定义:
如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。
通俗的来说 继承 顾名思义 是一种继承关系。在父与子的关系中:父类: 被继承的类叫父类;子类: 去继承的类叫子类。在对象和对象的关系上来讲:可以把类似狗和动物之间的这样的关系看成是一种继承的关系,需要通过编程语言去描述这种关系。从生活的角度来说,运动员与篮球运动员,交通工具与火车都是一种继承关系。
在Java中使用extends 关键字来实现类与类的继承关系 示例如下:
//建立了一个动物的父类
public class Animal {
public String name;//名字
public int legnum;//腿的个数
public void happy(){
System.out.println("叫");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLegnum() {
return legnum;
}
public void setLegnum(int legnum) {
this.legnum = legnum;
}
}
//建立了一个狗的子类
public class Dog extends Animal {
public Dog() {
}
public void f(){
System.out.println(name);
}
}
//一个测试类
public class Test{
public static void main(String[] args) {
Animal a = new Animal();// Animal 对象
a.setName = "小黑";
System.out.println(a.getName);
Dog d = new Dog();
d.setName("大黄") ;
d.f();
}
}
继承的特点:
- Java语言的继承关系:是一种单继承的关系
- 一个子类只能有一个父类,而一个父类可以有多个子类
- 子类可以可以使用父类的属性和方法 ,但是父类不能够访问子类独有的属性和方法
- 创建子类对象时 先执行父类的构造方法 ,然后在执行子类的构造方法
- 使用super关键字 去调用父类的构造方法。super父类的引用 超类的引用 基类的引用 用法和this关键字类似
示例:对于子类可以可以使用父类的属性和方法 ,但是父类不能够访问子类独有的属性和方法
//建立了一个狗的子类
public class Dog extends Animal {
public String eyecolor;//子类定义的,父类不能访问
//构造函数
public Dog() {
}
public void f(){
System.out.println(name);
}
}
示例:创建子类对象时 先执行父类的构造方法 ,然后在执行子类的构造方法
//建立了一个动物的父类
public class Animal {
public String name;//名字
public int legnum;//腿的个数
//构造函数
public Animal(){
System.out.println("This is Animal ");
}
public void happy(){
System.out.println("叫");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLegnum() {
return legnum;
}
public void setLegnum(int legnum) {
this.legnum = legnum;
}
}
//建立了一个狗的子类
public class Dog extends Animal {
public String eyecolor;//子类定义的,父类不能访问
//构造函数
public Dog() {
System.out.println("This is Dog ");
}
public void f(){
System.out.println(name);
}
}
//一个测试类
public class Test{
public static void main(String[] args) {
Dog d = new Dog();
d.setName("大黄") ;
d.f();
}
}
示例:对于有参父类构造函数,子类有参构造函数使用super关键字
//父类中构造函数
public Animal(String name,int legnum){//有参数
System.out.println("This is Animal");
this.name = name;
this.legnum = legnum;
}
//子类构造函数
public Dog(String name,int legnum){
super(name, legnum);
System.out.println("This is Dog");
}
public class Test{
public static void main(String[] args) {
Dog d = new Dog("Tom",4);
d.f();
}
}
练习:
如果在父类中加入静态代码块 在子类中也加入静态代码块 那么创建子类对象时,它的执行顺序是什么样子的?
代码:
// Animal加入的静态代码块
static{
System.out.println("This is static Animal");
}
// Dog类添加的静态代码块
static{
System.out.println("This is static Dog ");
}
//一个测试类
public class Test{
public static void main(String[] args) {
Dog d = new Dog("Tom",4);
d.f();
}
}
//运行结果
This is static Animal
This is static Dog
This is Animal
This is Dog
Tom
重写(Override)
满足条件:
- 一定发生在两个类中(父-子的关系 祖--孙的关系)一定是继承关系
- 访问修饰符相同 返回类型相同 方法名字相同 方法体不同 子类的访问修饰符不能比父类更严格
- 重写是多态的表现特征之一
示例: 对于父类中的happy函数在子类中进行重写,结果是打印的是子类中的happy函数
//建立了一个狗的子类
public class Dog extends Animal {
public String eyecolor;//子类定义的,父类不能访问
//静态代码块
static{
System.out.println("This is static Dog ");
}
//构造函数
public Dog(String name,int legnum){
super(name, legnum);
System.out.println("This is Dog constructor");
}
public void f(){
System.out.println(name);
}
//子类中重写
public void happy(){
System.out.println("wangwang");
}
}
多态
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
比如你是一个酒神,对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒,从外面看我们是不可能知道这是些什么酒,只有喝了之后才能够猜出来是何种酒。你一喝,这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下:
酒 a = 剑南春
酒 b = 五粮液
酒 c = 酒鬼酒
…
这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类,我们只是通过酒这一个父类就能够引用不同的子类,这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象。
引用数据类型转换
基本数据类型的转换:大类型转小类型 -----强制转换;小类型转大类型 -----自动转换
向上转型和向下转型:强制转换和自动转换
向上转型对应着:自动转换
向下转型对应着:强制转换
满足条件:两者之间要存在继承或者是实现关系(接口)
示例:这里的多态是具体的动物
//动物类
public class Animal {
public String name;
public int legnum;
static{
System.out.println("This is static Animal");
}
public Animal(String name,int legnum){
System.out.println("This is Animal constructor");
this.name = name;
this.legnum = legnum;
}
/**
* 描述动物开心了 应该怎么叫
*
* 子类更具体 父类更抽象
*
*/
public String happy(){
return "叫";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLegnum() {
return legnum;
}
public void setLegnum(int legnum) {
this.legnum = legnum;
}
}
//Dog类
public class Dog extends Animal {
public String eyecolor;
static{
System.out.println("This is static Dog ");
}
public Dog(String name,int legnum){
super(name, legnum);
System.out.println("This is Dog constructor");
}
// 对子类独有的属性进行初始化
public Dog(String name,int legnum,String eyecolor){
super(name, legnum);
this.eyecolor = eyecolor;
System.out.println("This is Dog constructor");
}
public void f(){
System.out.println(name);
}
public String happy(){
return "wangwang!!!!";
}
}
//Child类
public class Child {
public String name;
public int age;
public Child(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 每个孩子都有自己的宠物 每一个宠物happy了应该怎么叫
*/
public void childPetHappy(Animal a){
System.out.println(this.getName()+"养了"+a.getName()+"这个宠物开心了"+a.happy()+"叫");
}
}
//Cat类
public class Cat extends Animal{
public Cat(String name,int legnum){
super(name, legnum);
}
@Override
public String happy() {
return "miaomiao !!!!!";
}
}
//测试类
public class Test {
public static void main(String[] args) {
Child c1 = new Child("lili", 10);
Child c2 = new Child("marry", 11);
Dog d= new Dog("honey", 4);
Cat c = new Cat("tom",4);
c1.childPetHappy(d);
c2.childPetHappy(c);
//父类对象a 表示父类的引用
//子类可以使用父类的属性和方法,父类不可以使用子类独有的属性和方法
Animal a=new Dog("小白",20);
Dog dd=(Dog)a;
dd.eyecolor="红色";
System.out.println(a.happy());
}
}
instanceof 关键字
用于判断:对象是否属于后面的类型,如果属于则返回true 如果不属于则返回false
示例:
public class Test {
public static void main(String[] args) {
Child c1 = new Child("lili", 10);
Child c2 = new Child("marry", 11);
Dog d= new Dog("honey", 4);
Cat c = new Cat("tom",4);
//父类对象a 表示父类的引用
//子类可以使用父类的属性和方法,父类不可以使用子类独有的属性和方法
Animal a=new Dog("小白",20);
Dog dd=(Dog)a;
dd.eyecolor="红色";
//判断a的类型是否是Animal
if(a instanceof Animal) {
System.out.println(true);
// 类型的转换
}else{
System.out.println(false);
}
}
}
JVM虚拟机栈-局部变量表
局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内定义的局部变量。局部变量表的容量以变量槽(Variable Slot)为最小单位,Java虚拟机规范并没有定义一个槽所应该占用内存空间的大小,但是规定了一个槽应该可以存放一个32位以内的数据类型。
局部变量:
- 8种数据类型:boolean、byte、char、short、int、float、reference和returnAddress类型的数据
- 对象的引用 (reference类型)它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与对象相关的位置。
- 方法的返回值( return address) returnAddress类型是为jsr、jsr_w和ret指令服务的,目前已经很少使用了。
例子:
public class Test111 {
public static void main(String[] args) {
int a=3;
int b=3;
String key1=new String("123");
String key2=new String("123");
String key="123";
Sreing result = "123";
System.out.println( a==b);//结果是ture
System.out.println(key==result );//结果是ture
System.out.println( key==key1);//结果是false
System.out.println(key1==key2 );//结果是false
//双等号比的是地址
}
}
简单的图示:
在局部变量表中是一个32位的空间 针对于long类型double类型 都是64位 为了存储这两个类型 开辟2个slot的空间进行存储
局部变量表存储的内容 都是有一定生命期限,灵活性比较差 但是运行速度是比堆空间要快。
堆空间 存储的内容 是没有生命期限的 灵活性比较好,因为JVM管理的是一个整个比较大的空间,所以运行速度相对较慢,那么堆空间所存储的内容,回收机制是由GC 垃圾回收器来完成的。在Java中 垃圾回收器不由我们程序员来操控 由JVM来操控,当虚拟机关闭,也不是马上就对 堆空间存储的内容进行清理,而是等待整个CPU及线程空闲的情况下进行自动清理。