什么是封装?
封装就是将类的部分属性和方法隐藏起来,不允许外部程序直接访问,只能通过该类公开提供的方法来访问类中定义的属性和方法,封装是面向对象的三大特征之一。
如何使用封装?
示例:
创建一个Person类
public class Person {
public String name;//姓名
public int age;//年龄
public String secret;//秘密
public Person(String name,int age,String secret){
this.name=name;
this.age=age;
this.secret=secret;
}
}
修改属性的可见性:将类中定义的所有属性全部修改为private修饰
public class Person {
private String name;//姓名
private int age;//年龄
private String secret;//秘密
public Person(String name,int age,String secret){
this.name=name;
this.age=age;
this.secret=secret;
}
}
再去直接修改年龄值,就会报错
public class PersonTest {
public static void main(String[] args){
Person p1 = new Person("刘德华",54,"双重人格");
p1.age=30;//报错
}
}
创建公开的getter/setter方法:用于读取/修改属性值
public class Person {
private String name;//姓名
private int age;//年龄
private String secret;//秘密
public Person(String name,int age,String secret) {
this.name=name;
this.age=age;
this.secret=secret;
}
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;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}
public class PersonTest {
public static void main(String[] args){
Person p1 = new Person("刘德华",54,"双重人格");
p1.setName("伍六七");
String name = p1.getName();
}
}
在getter/setter方法中加入控制语句:用于对属性值的合法性校验
在类中,对应的属性进行增加校验语句
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0) {
System.out.println("年龄不合法,必须大于0");
} else {
this.age = age;
}
}
在方法中
public class PersonTest {
public static void main(String[] args){
Person p1 = new Person("刘德华",54,"双重人格");
p1.setAge(-1);
//输出
//年龄不合法,必须大于0
}
}
public void setAge(int age) {
if (age < 0 || age > 200) {
System.out.println("年龄不合法,必须大于0并且小于200");
} else {
this.age = age;
}
}
什么是包?
包时Java中的一个专业词汇,包的本质就是一个文件夹。
为什么要使用包?
如何创建包?
语法:
package 包名;
如何引入包?
为了使用不在同一包中的类,需要再Java程序中使用import关键字引入这个类
语法:
import 包名.类名;
package com.ly.chat11;
//类的全限定名:包名+'.'+类名
import java.util.Scanner;//告诉JVM,到Java.util包下去找一个名为Scanner的类
public class User {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
}
}
为什么要引入包?
因为JVM只能识别当前包下所有的类,如果要使用当前包之外的其他包的类,那必须告诉JVM,使用的是哪一个包中的哪一个类。
一个类同时引用两个来自不同包的同名类,必须通过完整类名(类的全限定名)来区分
Java.lang 包
属于Java语言的开发包,该包中的类可以直接拿来使用,而不需要引入包。因为JVM会自动引入
比如:我们经常使用的System,String,Math
Java.util 包
属于Java提供的一些使用类以及工具类。
比如:我们经常使用的Scanner
概念:
访问修饰符就是控制访问权限的修饰符号
类的访问修饰符:
类的访问修饰符只有两种:
public修饰符修饰类表示类可以公开访问。
默认修饰符修饰类,表示该类只能在同一个包中访问
类成员访问修饰符:
类成员包括了成员属性和成员方法。
类成员访问修饰符换言之就是成员属性和成员方法的访问修饰符。
static修饰符应用范围:
static修饰符只能用来修饰类中定义的成员变量,成员方法,代码块以及内部类(内部类有专门的章节进行讲解)
static修饰成员变量:
static修饰成员变量称之为类变量。属于该类所有成员共享
假如country初识值为:“中国”,修改之后为“日本”,那么再去调用值就为“日本”
不是成员变量,不会随着成员而改变
如果类变量是公开的,那么可以使用类名.变量名直接访问该类变量
static修饰代码块:
static修饰代码块称为静态代码块,在JVM第一次记载该类时执行。
因此,静态代码块只能够被执行一次,通常用于一些系统设置场景。
static {
}
概念:
继承的概念简单而强大,当你要创建一个新类,并且已经有一个包含所需代码的类时,可以从现有类中派生出来新类。这样,你可以重用现有类的字段和方法,而不必自己编写(调试)它们。
子类从其父类继承所有成员(字段,方法和嵌套类),构造方法不是成员,因此他们不会被子类继承,但是可以从子类中调用父类的构造方法。
从一个类派生出来的类叫作子类(也可以是派生类,拓展类或者子类),派生子类的类叫作超类(也称为基类或者父类)
继承也是面向对象的三大特征之一。
如何使用继承?
语法:
publis class 子类名 extends 父类名{
}
示例:
public class Person{
public String name;
public String sex;
public int age;
public void eat(){
System.out.println("吃饭");
}
}
public class PersonTest extends Person{
public void show(){
System.out.println(name);
//本类中未定义name变量,但却可以使用,说明name变量是从父类中继承过来的
}
}
继承的属性和方法:
无论子类在什么包中,子类会继承父类所有公开的和受保护的成员(包括字段和方法)。如果子类和父类在同一个包里,子类也会继承父类中受包保护的成员。
子类不会继承父类中定义的私有成员,尽管如此,如果父类中有提供公开或者受保护的访问该字段的方法,这些方法也能在子类中被使用
重复性代码:
public class Person{
public String name;
public String sex;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃饭");
}
}
医生特有类:
public class Doctor extends Person{
private String professional;
public String getProfessional() {
return professional;
}
public void setProfessional(String professional) {
this.professional = professional;
}
public void cure(){
System.out.println("治病");
}
}
测试,创建对象:
public class PersonTest{
public static void main(String[] args) {
Doctor d =new Doctor();
d.setName("Miss");
d.setSex("女");
d.setAge(19);
d.setProfessional("临床");
//优化之后
Person p1 = new Doctor();
p1.setName("Miss");
p1.setSex("女");
p1.setAge(19);
p1.setProfessional("临床");//报错,因为该类不在Person里
//但是我们可以使用强制类型转换
((Doctor)p1).setProfessional("临床");
}
}
子类和父类的关系是is-a关系,表示一个
如果一个对象赋值给其父类引用,此时想要调用该对象的特有的方法,必须要对其进行强制类型转换
子类中的一个成员方法与父类中的成员方法有相同的签名(方法名加上参数数量和参数类型)和返回值类型的实例方法重写了父类的方法
如何使用方法重写:
子类重写方法的能力使类可以从行为“足够近”的父类继承,然后根据需要修改行为,重写方法与被重写的方法具有相同的名称,数量和参数类型,并且返回类型相同,重写方法还可以返回重写方法返回的类型的子类型,此子类型称为协变返回类型。
举例:
public Number getScore(){
return 0;
}
子类重写父类的方法时,返回值类型可以是父类方法的返回值类型的子类
重写方法时的访问修饰符级别不能降低
public Integer getScore(){
return 90;
}
重写方法时,你可以需要使用 @override 来注解,该注释指示编译器你打算重写父类中的方法。如果由于某种原因,编译器检测到该方法在父类中不存在,则它将生成错误。
之前我们所学习的数字包括byte short int long float double类型
那么他们所对应的number的子类: Byte Short Integer Long Float Double
概念:
如果子类的构造方法没有明确调用父类的构造方法,Java编译器会自动插入一个父类无参构造的调用。如果父类没有无参构造,你将得到一个编译时错误。
object类有一个无参构造,因此,如果object类是唯一的父类,这就没有问题。
示例一:子类和父类中都没有定义构造方法
父类:
public class Person{
public String name;
public Person(){
super();
}
public Number getScore(){
return 0;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
子类:
public class Doctor extends Person{
private String professional;
//如果一个类中没有定义构造方法,那么编译器将会给该类插入一个无参构造方法
public Doctor(){
super();//如果子类构造方法中没有明显调用父类的构造方法,那么编译器会
//自动插入一个父类的无参构造的调用
}
public String getProfessional() {
return professional;
}
public void setProfessional(String professional) {
this.professional = professional;
}
public void cure(){
System.out.println("治病");
}
}
示例二:子类有定义构造方法,父类没有定义构造方法
父类:
public class Person{
public String name;
// public Person(){
// super();
// }
public Number getScore(){
return 0;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
子类:
public class Doctor extends Person{
private String professional;
public Doctor(){
super();
}
public Doctor(String name){
super();
this.name = name;
}
public String getProfessional() {
return professional;
}
public void setProfessional(String professional) {
this.professional = professional;
}
public void cure(){
System.out.println("治病");
}
}
示例三:子类和父类中都有定义构造方法
父类:
public class Person{
public String name;
public Person(String name,String sex){
this.name = name;
this.sex = sex;
}
public Number getScore(){
return 0;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
子类:
public class Doctor extends Person{
private String professional;
public Doctor(String name,String sex){
super(name,sex);
//如果父类中定义了带参构造,并且没有定义无参构造,
//那么必须在子类的带参构造方法中显示的调用父类的带参构造
}
public String getProfessional() {
return professional;
}
public void setProfessional(String professional) {
this.professional = professional;
}
public void cure(){
System.out.println("治病");
}
}
使用super调用父类的构造方法时,必须为这个构造方法的第一条语句
public class Doctor extends Person{
private String professional;
public Doctor(String name,String sex){
//报错,不是第一条语句
System.out.println("abc);
super(name,sex);
}
}
如果你的方法重写了父类的方法之一,则可以通过使用关键字super来调用父类中被重写的方法。
你也可以使用super来引用隐藏字段(尽管不建议使用隐藏字段)
隐藏字段:
父类:
public class Person{
protected String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
子类:
public class Doctor extends Person{
private String name;
public Doctor(String name){
this.name = name;
}
}
public class PersonTest{
public static void main(String[] args) {
Doctor d = new Doctor("Mis");
System.out.println(d.getName());
//null
}
}
如果想得到对应的name,可以重写方法
子类:
public class Doctor extends Person{
private String name;
public Doctor(String name){
this.name = name;
}
@Override
public String getName() {
return name;
}
}
如果既想得到父类的变量,又想得到子类的变量呢?
子类:
public class Doctor extends Person{
private String name;
public Doctor(String name){
this.name = name;
}
public void show(){
System.out.println(this.name);//访问本类中定义的name变量
System.out.println(super.name);//访问父类中定义的变量
}
}
如果子类和父类中没有相同的成员变量,此时使用this和super均可以调用父类的成员变量
测试:
public class PersonTest{
public static void main(String[] args) {
Doctor d = new Doctor("Mis");
System.out.println(d.getName());
d.show();
}
}
除了没有父类的Object之外,每个类都有一个且只有一个直接父类(单继承)。在没有其他任何显式超类的情况下,每个类都隐式为Object的子类。
类可以派生自另一个类,另一个类又可以派生自另一个类,依次类推,并最终派生自最顶层的类Object。据说这样的类是继承链中所有类的后代,并延伸至Object。
所有类都是Object的子类,因此,创建对象时都需要调用Object类中的无参构造方法,而Object本身就表示对象,因此创建出来的都是对象
应用范围:
final修饰符应该使用在类,变量以及方法上
你可以将类的某些或者所有方法声明为final。在方法声明中使用final关键字表示该方法不能被子类覆盖。
object类就是这样做的----它的许多方法都是最终的
如果一个类被final修饰,表示这个类就是最终的,因此这个类不能够被继承,因为继承就是对类进行拓展
public final class Person{
public void show(){
System.out.println("这里是最终类里的方法");
}
}
子类直接报错
public class Doctor extends Person{
}
注: 你也可以声明整个类的final,声明为final的类不能被子类化(继承)。
例如:当创建不可变类(如String类)时,这特别有用
public class Person{
public final void show(){
System.out.println("这是一个最终方法,不能被重写");
}
}
直接报错
public class Doctor extends Person{
public void show(){
}
}
final修饰变量的时候,变量必须在对象构建时完成初始化。
final修饰的变量称为常量
public class Doctor extends Person{
private final int number;
public Doctor(){
this.number = 10;
}
}