一、this关键字
在编程时,为了区分成员变量和局部变量,在编码时,可以使用this关键字进行指示, 使用this调用的是成员变量或者成员方法,还有构造方法. this在实际运行时,表示当前正在调用此方法的对象 this表示当前对象
this的用法:
public class Student { int number; String name; String gender; public Student(){ //赋予一些默认值 this(102,"李四","女"); } public Student(int number,String name,String gender){ //等号左边为成员变量,右边为局部变量(入参) this.number = number; this.name = name; this.gender = gender; } //this指代当前对象 public void study(){ System.out.println(this.name+"好好学习"); this.exam(); } public void exam(){ System.out.println(this.name+"认真考试"); } }
二、static关键字
static被称为静态,可以用来修饰类的属性,方法,代码块,内部类,静态类在内存中只存在一份
(1)static修饰的成员变量在内存中只有一份,适合将所有实例都相同的属性设计为静态(中国人类 国籍都是中国),访问时直接使用类名访问,static修饰后的成员,随着类的加载而加载,先于对象而存在
静态变量的默认值规则和实例变量一样,静态变量值是所有对象共享
(2) static修饰方法:静态方法只能访问静态的变量,不能访问非静态的变量.在方法中不使用非静态成员变量时,可以将方法设计为静态.
(3) 当类被加载时,静态的成员就会加载,先于对象创建存在,静态的先执行,可以被类,对象访问, 非静态的只能通过对象访问
- 类什么时候被加载: 通过类名访问类中静态成员时,类会被加载 在一个类中使用main方法,也会加载类 创建对象也会加载类
package day2.staticdemo; public class StaticDemo { String name; static String country ="中国"; /* static关键字修饰的方法就是静态方法,属于类,可以通过类名直接进行访问 当方法中不需要使用非静态的成员变量时候,我们可以将方法设计为静态方法,不需要创建对象,直接通过类名访问 */ public static void test1(){ System.out.println(this.name); //在静态方法中不能使用非静态的成员,因为静态的成员随着类的加载而加载,类加载先于对象 System.out.println(country); } /* 非静态成员方法中,可以使用静态成员变量,因为静态变量先加载 */ public void test(){ System.out.println(country); } public static void main(String[] args) { StaticDemo.test1(); } }
三、代码块
(1)实例代码块:每次创建对象时自动调用
{ System.out.println("Demo实例代码块1"); }
(2)静态代码块:类加载时自动调用,仅一次,与是否创建对象无关
static { System.out.println("Demo静态代码块1"); }
如果有多个实例代码块或多个静态代码块,他们会按照先后顺序执行,实例代码块会先于构造方法执行.
四、包
问题:随着程序架构越来越大,会出现维护难的问题,尤其同名问题,同时为了便于管理,引入包的机制
定义:使用package关键字修饰包,包称为类的命名空间(可以理解为是一个文件夹),是类名的组成部分,即全类名 = 包名 + 类名简称
作用:(1)避免类的同名问题,将其放入不同的包内
(2)包的层次可以方便按照不同的功能管理类
(3)控制访问权限
命名规范:前提:包名全为小写,用.号来区分包的级别
第一级 指该项目的类型,如com,org,gov等
第二级 指项目所开发或者运行的公司名称,如:oracle,sun,huawei等
第三级 指项目的名称,如:bcms,oa,erp,cms等
第四级 指项目模块的名称,如:bean,action,exception等
在使用其他包中的类时,需要通过import关键字来导入,但不能一次导入两个名称相同不同包的类
import java.util.Date; public class Pdemo { public static void main(String[] args) { new Date(); //由于上面已经导入一个util包中的Date类,故下面Date类用全名进行调用,不可一次导入两个名称相同但类不同的包 new java.sql.Date(10); } }
五、访问权限修饰符
(1)public :公共权限 修饰类、属性、方法。可以在任意类中访问
(2)protected:受保护的权限 修饰属性、方法。可以在同包类访问,如果 不是同包类,必须是该类的子类才可以访问
(3)(default):同包权限(默认修饰符) 修饰类、属性、方法。只能在同包的类访问
(4)private:私有权限 修饰属性、方法。 只能在本类中访问
图解:
六、面向对象语言的三大特征:继承、封装、多态
1、封装
概念:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是 通过该类提供的方法来实现对隐藏信息的操作和访问
其本质为:使用权限修饰符控制成员对外的可见性
封装案例1:将属性(成员变量)私有化
package com.ffyc.javaoop.day3.fz; public class Person { /* 将成员变量设置为私有权限,在其他类中就不能直接访问 */ private String name; private int age; public Person() { } //外界可以通过构造公共权限的构造方法方法对私有成员进行赋值 //但是需要使用成员变量的值时,就不能获取到 //给私有属性对外提供的公共全称的方法进行赋值和值的获取 public void setName(String name){ if(name.length()>2&&name.length()<5){ this.name = name; } } public String getName(){ return this.name; } public void setAge(int age){ if(age>=0&&age<150){ this.age = age; } } public int getAge(){ return this.age; } }
封装案例2:将某些方法私有化
解决一类问题的固定方式 单例模式: 单个实例,在系统中,想让某个类只能创建一个对象
public class MyWindow { //定义一个静态变量,用来接收唯一的一个对象 static MyWindow myWindow=null; //将构造方法私有化,这样在其他类中,就无法使用构造方法,就不能创建对象 private MyWindow(){ } //对外提供的获取唯一对象的公共方法 public static MyWindow getMyWindow(){ if(myWindow==null){ myWindow = new MyWindow(); } return myWindow; } }
2、继承
(1)定义:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么,多个类中无需再定义这些属性和行为,只需要和抽取出来的类构成继承关系
(2)优点:继承的出现减少了代码冗余,提高了代码的复用性。
继承的出现,更有利于功能的扩展。
继承的出现让类与类之间产生了is-a的关系,为多态的使用提供了前提。
(3)语法:通过extends关键字声明一类继承于另一类
public class Animal extends Object { private String name; private int age; public void eat(){ System.out.println("动物吃东西"); } } public class Dog extends Animal{ public void lookHome(){ System.out.println("狗可以看家"); } }
(4)注意事项:
-
类 java.lang.Object,是类层次结构的根类,即所有其它类的父类,每个类都使用 Object作为超类,当一个类没有显示的继承其他类时,默认继承Object类
-
子类继承父类后,拥有父类所有的实例变量和方法,但是不能直接访问私有成员和方法
-
java中一个类不能继承多个类,只能直接继承一个类,但是一个父类可以有多个子类,可以多层继承
(5)方法重写
引入:当父类的方法功能实现不能满足子类需求时,可以对方法进行重写( override),子类可以对从父类中继承来的方法进行改造,我在程序执行时,子类的方法将覆盖父类的方法。有时也称称方法的重写为方法的覆盖
注意:构造方法,静态方法不能重写,成员变量不存在重写
语法规则:1.子类重写的方法必须和父类被重写的方法名称,参数列表相同。
2.子类重写的方法的返回值类型与父类保存一致。
3.子类重写的方法使用的访问权限不能小于父类被重写方法的访问权限。
注意:① 父类私有方法不能重写 ② 跨包的父类默认权限的方法也不能重写
4.子类方法抛出的异常不能大于父类被重写方法的异常
@Override:
@Override是java中定义的注解标签,用来进行标记,写在方法上面,表示此方法是从父类重写而来,用来检测是不是满足重写方法的要求
(6)super关键字:在子类中使用super关键字,访问父类中定义的那部分成员.
作用:super可用于访问父类中定义的属性
super可用于调用父类中定义的成员方法
super可用于在子类构造器中调用父类的构造器
误区: 不要把super误认为是父类对象,在创建子类对象时,不会创建父类对象. 只会将父类中的信息加载到子类对象中存储.
public class Dog extends Animal { public void eat() { super.eat();//调用父类中的eat() System.out.println("狗吃骨头");//扩展自己子类吃东西的功能 } public void lookHome(){ this.eat(); //调用的当前对象的eat() super.eat();//在子类中调用父类中的那部分定义的成员 System.out.println("狗可以看家"); } }
super的追溯不仅限于直接父类还可以是父类的父类
(7)继承中的构造方法
子类继承父类时,不会继承父类的构造方法。只能通过“super(形参列表)” 的方式调用父类指定的构造方法
规定super(形参列表),必须声明在构造器的首行
如果在子类构造器的首行没有显示调用super(形参列表),则子类此构造器 默认调用super(),即调用父类中空参的构造器
这么做是为了保证先对父类成员进行初始化
注意:如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有空参的构造器,则编译出错
public class Dog extends Animal { /* 每当创建子类对象时,会调用子类的构造方法,在子类中的构造方法中,调用父类的构造方法. 而且在子类构造方法的第一行的就会调用父类构造方法.先确保父类中的成员被初始化 */ public Dog(){ /* 子类构造方法中默认会调用父类无参构造方法, 如果需要显示的使用super调用,必须放在构造方法的第一行 还可以调用父类中指定的构造方法 */ // super(); System.out.println("Dog无参构造方法"); } public Dog(String name, int age) { super(name, age); } @Override public void eat() { System.out.println("狗吃骨头");//扩展自己子类吃东西的功能 } public void lookHome(){ System.out.println("狗可以看家"); } }
-
补充:成员变量与局部变量
在类中的位置不同
成员变量:在类中定义 局部变量:在方法中定义或者方法的参数
权限修饰不同
成员变量:可以使用权限修饰符 局部变量:不可以使用权限修饰符
初始化不同
成员变量:创建对象后,由构造方法初始化 局部变量:没有默认初始化值,必须定义,赋值
生命周期不同
成员变量:随着对象的创建而存在,随着对象的销毁而消失 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
在内存中的位置不同
成员变量:与对象一起在堆内存中 局部变量: 与方法一样在栈