封装
成员变量私有化,提供公有的get和set方法访问变量
封装就是不允许直接访问成员变量,必须通过set和get方法来访问;
优点:安全,便于重构
良好的封装能够减少耦合。
类内部的结构可以自由修改。
可以对成员变量进行更精确的控制。
隐藏信息,实现细节。
示例:
public class Kid {
private int age;
public int getAge() {//通过get方法获取变量值
return age;
}
public void setAge(int age) {//通过set方法,将入参赋值给变量
this.age = age;
}
}
this关键字
this关键字,表示当前类的对象
this关键字在程序中三种常见的用法:
- 通过 this 关键字可以明确地去访问一个类的成员变量,解决与局部变量名称冲突的问题;
- 通过 this 关键字调用成员方法;
- 构造方法是在实例化对象时被Java虚拟机自动调用的,在程序中不能像调用其他方法一样去调用构造方法,但是可以在一个构造方法中去使用 "this([参数1,参数2...])"的形式去调用其他构造方法。
使用 this 调用类的构造方法时需要注意以下几点:
- 只能在构造方法中使用 this 关键字去调用其他的构造方法,不能在成员方法中使用this关键字调用构造方法;
- 在构造方法中,使用 this 关键字调用构造方法的语句必须放在第一行,且只能出现一次;
- 不能在一个类的两个构造方法中使用 this 互调,这种写法会编译报错。
1.2 访问控制修饰符
访问控制修饰符,用来控制访问权限,一共有四个
修饰符 | 本类 | 同包 | 不同包子类 | 不同包的其他类 | |
私有的 | private | √ | |||
默认 | √ | √ | |||
受保护的 | protected | √ | √ | √ | |
公共的 | public | √ | √ | √ | √ |
2 继承
通过关键字extends来声明子类与父类的继承关系,子类 extends 父类
示例:
public class Kid extends Person{}
特点:
1.所有类都有父类,即所有类都派生于Object类
2.只能单亲继承,即每一个子类只能有一个父类
3.子类只能继承父类的非private修饰的变量和方法
子类不能继承父类的私有属性, 如果子类中公有的方法影响到了父类私有属性, 那么私有属性是能够被子类使用的(即通过父类的公有方法访问到父类的私有变量)
4.子类可以直接使用继承的变量和方法,不需要再在子类中声明或写出
2.1 构造方法constructor
构造方法(又叫构造器)是一种特殊的方法,它的作用是在创建对象的时候 ,完成对象成员变量的初始化。
特点:
- 方法名与类名一致
- 没有返回值也没有void
- 通过new关键字调用
- 当一个类没有显示的声明构造方法时,java会默认创建一个无参构造方法
- 构造方法可以重载
示例:
public class Kid extends Person{
private int age;
public Kid() {//无参构造方法
}
public Kid(int age) {//有参构造方法
setAge(age);
}
public void setAge(int age) {
this.age = age;
}
}
2.2 super关键字
表示当前类的父类对象,可以使用super关键字实现对父类变量和方法的访问
注意:在子类的构造方法中,无论写不写super(),java都会默认使用super()调用父类的构造方法
示例:
public Kid() {//无参构造方法
super();//调用父类构造方法
}
public void setAge(int age) {
super.password = "123";//调用父类变量并赋值
this.age = age;
}
2.3 重写
子类继承了父类的方法,对父类的方法中的执行代码进行修改以满足子类业务的需要,这就是重写。
特点:
- 重写发生在子父类当中
- 方法名、参数列表、返回值类型均相同
- 重写的方法,方法体不同或者访问控制修饰符不同
- 子类方法的访问权限不能缩小
- 静态方法(static)不能进行重写(因为静态资源只加载一次)
示例:
public class Father {
public void speak() {
System.out.println("i am father!!!");
}
}
public class Son extends Father{
@Override
public void speak() {
System.out.println("i am son!!!");
}
}
2.4 重写与重载的区别
重写 | 重载 | |
发生位置 | 子父类中 | 同一个类中 |
改变的位置 | 访问控制修饰符不同 方法体不同 | 参数列表不同 |
不变的位置 | 方法名、参数列表、返回值类型 都不变 | 方法名不变 |
3 多态
没有继承就没有多态,生成的对象,在调用父类方法时,如果方法被子类重写,则调用的是子类重写的方法。
代码当中体现多态性,其实就是一句话: 父类引用指向子类对象
格式:父类 对象名 = new 子类();
3.1 抽象类
抽象类不能被实例化(不能new对象),它的作用是提供给其他类进行继承。
继承关键字 abstract
修饰类,类为抽象类,不能被实例化;
修饰方法,方法为抽象方法,只有方法的签名,没有方法体;
抽象类特点:
- 抽象类不能实例化,即抽象类不能创建对象;
- 子类继承(extends)抽象类,必须实现该抽象类当中所有的抽象方法;
- 抽象类,可以包含抽象方法和非抽象方法(普通方法)以及变量;
- 如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误;
- 抽象类可以有父类,但是父类必须有一个无参的构造函数,否则,抽象类必须声明一个与父类相同的有参构造方法;
示例:
// 抽象类
public abstract class Person{
String name;
public abstract void login(String userName, String password);
public abstract void register(String phone);
public void pay() {
System.out.println("支付");
}
}
// 子类
public class User extends Person {
@Override
public void login(String userName, String password) {
// TODO Auto-generated method stub
}
@Override
public void register(String phone) {
// TODO Auto-generated method stub
}
}
3.2 接口
接口是方法签名的集合
声明接口关键字 interface
实现接口关键字 implements
接口的特点:
- 用interface关键字声明接口;
- 子类实现接口,并重写接口的所有的签名方法;
- 接口只有方法的签名和变量;
- 接口的变量,会默认用public final static修饰;
- 接口的签名方法,会默认用public abstract修饰;
- 接口不能自身实例化,接口的实现类可以实例化;
- 接口可以实现多个,而父类只有一个(单亲继承),而且必须先继承(extends)父类再实现(implements)接口;
接口的优点:
- 解决Java中的单亲继承问题(继承只能单亲继承,但是一个类可以实现多个接口)
- 接口可以实现并行开发
- 便于重构
示例:
//接口
public interface Father {
//方法签名
public void speak(String str);
}
//实现类
public class User extends Person implements Father,Mother{
@Override
public void speak(String str) {
// TODO Auto-generated method stub
}
}
3.3 类型转换
3.3.1 向上转型:子类对象 向父类转型
- 将一个【父类的引用】指向一个子类对象,称为向上转型;此时自动进行类型转换(即可以理解为创建了一个父类类型的子类对象)
- 通过父类的引用调用的方法,是子类重写或继承父类的方法,而不是父类原本的方法,更不是子类特有的方法;
- 通过父类的引用无法调用子类特有的方法,即向上转型的子类对象只能调用继承自父类的方法,而不能调用子类独有的方法,方法数量缩小,安全
示例:
class Kid extends Man
Man man = new Kid();
3.3.2 向下转型:父类对象 向子类转型
父类对象向子类转换需要强制类型转换;
- 将一个指向子类对象的父类引用赋给一个子类的引用,称为向下转型
- 只有Object有向下转型的可能
示例:
class Kid extends Man
Man man = new Man();//创建了一个父类对象
Kid kid = (Kid) man; //强制类型转换,将父类对象强制转换成子类类型
final关键字
final关键字,表述为“最终的,不可更改的” 用来修饰类、方法和变量。
特点:
- final修饰的类不能够被继承;
- 修饰的方法不能被重写;
- 修饰的变量为常量,不可修改,且声明常量的同时要给常量赋值。
final关键字修饰的变量,称为常量——常量名称必须都为大写
- 修饰基本数据类型,变量的值不能被改变
- 修饰引用类型(对象),该对象的引用(内存地址)不能被改变,即对其初始化之后便不能再让其指向另一个对象
示例:
final int NO = 12;
final String NAME = "abc";
static关键字
static关键字,表述为“静态的,全局的”,被static修饰的资源(变量或方法),可以直接通过类名调用,而不需要实例化
JVM的类加载顺序
static声明的静态资源 > new > {代码块} > 构造方法constructor
特点
- static声明的资源只能被初始化一次,且在整个程序编译通过之后,开始运行之前完成初始化;
- 修饰变量,称为静态变量,局部变量(如方法中的变量)不能被static 修饰,因为static就有全局的意思;
- 修饰方法,称为静态方法,静态方法只能调用其他静态资源,不能调用非静态变量,不能应用this和super,因为静态资源的加载先于实例化;
- 被static修饰的变量和方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被该类的所有实例共享
- 修饰内部类(静态类),外部类不需要实例化,可以直接通过外部类名调用
示例:
public class Man {
//静态变量
public static int no;
//静态方法
public static void speak(String str) {
System.out.println(str);
}
//主方法
public static void main(String[] args) {
//调用静态变量
Man.no = 12;
//调用静态方法
Man.speak("hello");
}
}
补充:
1. 实例方法和所属的实例绑定
解释:
同一个类中的各个对象都有各自的方法,互相没关系,互不影响。
2. 静态(static)方法和所属的类绑定
解释:
静态方法不会在实例化创建对象时,为对象创建一个新的static方法,所有的对象公用一个static方法,即多个实例对象先后调用该静态方法,只保存最后一次造作的结果。
3. 静态块
解释:
对静态变量进行初始化,每个静态代码块只会执行一次。
由于JVM在加载类时会执行静态代码块,所以静态代码块先于主方法执行。 如果类中包含多个静态代码块,那么将按照“先定义的代码先执行,后定义的代码后执行”。
注意:
- 静态代码块不能存在于任何方法体内
- 静态代码块不能直接访问实例变量和实例方法。
问题
父类: 静态块 构造方法
子类:静态块 构造方法
子类继承父类,创建子类对象,观察加载顺序
答案:加载顺序为1父类静态块2子类静态块3父类构造方法4子类构造方法
示例:
public class Man {
static {
System.out.println(" man static");
}
public Man() {
System.out.println(" man constructor");
}
}
public class Kid extends Man{
static {
System.out.println(" kid static");
}
public Kid() {
System.out.println(" kid constructor");
}
public static void main(String[] args) {
Kid kid = new Kid();
}
}
内部类
在类中定义的类,有普通内部类,静态内部类和匿名内部类
示例:
public class Man {
String name;
Kid kid;
//内部类
class Kid{
String name;
Integer age;
}
//静态内部类
static class Children{
}
public static void main(String[] args) {
Man man = new Man();
Kid kid = man.new Kid();
}
}