包的本质就是文件夹
作用:
- 可以避免类重名:有了包之后,类的全名称就变为:包.类名
- 分类组织管理众多的类,如果将所有的类文件都放在同一个包下,不利于管理和后期维护,所以,对于不同功能的类文件,可以放在不同的包下进行管理
- 可以控制某些类型或成员的可见范围。如果某个类型或者成员的权限修饰缺省的话,那么就仅限于本包使用
声明包的语法格式
package 包名;
使用包的规则和规范
- 必须在源文件的代码首行
- 一个源文件只能有一个声明包的语句
- 所有单词都小写,每一个单词之间使用.分割
- 习惯用公司的域名倒置
如何跨包使用类
前提:被使用的类或成员的权限修饰符是>缺省的,即可见的
- 使用类型的全名称,例如:java.util.Scanner input = new java.util.Scanner(System.in);
- 使用import 语句之后,代码中使用简名称,import语句告诉编译器到哪里去寻找类。
- 使用java.lang包下的类,不需要import语句,就直接可以使用简名称
- import语句必须在package下面,class的上面
- 当使用两个不同包的同名类时,例如:java.util.Date和java.sql.Date。一个使用全名称,一个使用简名称
概述
static是一个静态修饰符关键字,表示静态的意思,可以修饰成员变量和成员方法以及代码块。
static修饰成员变量
当 static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。定义格式:
静态成员变量的访问方式:
代码示例
public class Person {
// 非静态变量
String name;// 姓名
// 静态变量
static String country;// 国籍
// 构造方法
public Person() {
}
public Person(String name, String country) {
this.name = name;
this.country = country;
}
}
public class Test {
public static void main(String[] args) {
// 创建Person对象
Person p1 = new Person("张三", "中国");
System.out.println(p1.name+","+p1.country);// 张三,中国
System.out.println("=======================");
// 创建Person对象
Person p2 = new Person();
// 没有使用static修饰country
// System.out.println(p2.name+","+p2.country);// null,null
// 使用static修饰country
System.out.println(p2.name+","+p2.country);// null,中国
System.out.println("=======================");
System.out.println(Person.country);// 中国
}
}
static修饰成员方法
概述
-
被static修饰的方法会变成静态方法,也称为类方法,该静态方法可以使用类名直接调用。
代码示例
public class Person {
// 非静态方法
public void method1(){
System.out.println("Person method1...");
}
// 静态方法
public static void method2(){
System.out.println("Person method2...");
}
}
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.method2();
// 类名.静态成员方法名(实参);
Person.method2();
}
}
静态方法调用的注意事项:
- 静态方法中不能出现this关键字
- 静态方法中只能直接访问静态成员变量和静态成员方法
- 静态方法中不能直接访问非静态成员变量和非静态成员方法
- 非静态方法中可以直接访问一切成员变量和成员方法
以后开发中static的应用
- 以后的项目中,通常会需要一些“全局变量”或者“全局的工具方法”,这些全局变量和方法,可以单独定义在一个类中,并声明为static(静态)的,可以很方便的通过类名访问
static修饰代码块
- 在java中,被static修饰的代码块被称作静态代码块。static代码块随着类的加载而加载,而且只执行一次,可以用于成员的初始化,不需要建立对象,直接通过类名调用!当你的项目中有某些成员必须在对象建立前就初始化完毕,那就可以使用静态代码块!
static {
System.out.println("静态代码块");
}
继承
继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法。多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类中无需再定义这些属性和行为,只需要和抽取出来的类构成某种关系。如图所示:
多个类可以称为子类,也叫派生类;多个类抽取出来的这个类称为父类、超类(superclass)或者基类。继承描述的是事物之间的所属关系,这种关系是:is-a 的关系。例如,图中猫属于动物,狗也属于动物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。
继承的好处
- 我们可以将一些共性的属性,行为抽取到一个父类中,子类只需要继承即可,提供了代码的复用性
- 提高代码的扩展性。
- 类与类之间产生了关系,是学习多态的前提。
继承的格式
通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:
代码示例
class Animal {
// 定义name属性
String name;
// 定义age属性
int age;
// 定义动物的吃东西方法
public void eat() {
System.out.println(age + "岁的" + name + "在吃东西");
}
}
class Cat extends Animal {
// 定义一个猫抓老鼠的方法catchMouse
public void catchMouse() {
System.out.println("抓老鼠");
}
}
public class ExtendDemo01 {
public static void main(String[] args) {
// 创建一个猫类对象
Cat cat = new Cat();
// 为该猫类对象的name属性进行赋值
cat.name = "Tom";
// 为该猫类对象的age属性进行赋值
cat.age = 2;
// 调用该猫的catchMouse()方法
cat.catchMouse();
// 调用该猫继承来的eat()方法
cat.eat();
}
}
继承后构造方法的访问规则
- 构造方法的名字是与类名一致的。 构造方法不能被继承
- 子类中所有的构造方法默认都会访问父类中无参的构造方法 。子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super( )
如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?
- 通过使用super关键字去显示的调用父类的带参构造方法
- 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参的构造方法
继承后非私有成员的访问规则
- 当通过“子类”访问非私有成员时,先在子类中找,如果找到就使用子类的,找不到就继续去“父类”中找。
继承后私有成员的访问规则
- 父类中的成员,无论是公有(public)还是私有(private),均会被子类继承。
- 子类虽会继承父类私有(private)的成员,但子类不能对继承的私有成员直接进行访问,可通过继承的下来的非私有方法进行间接访问。如图所示:
继承的特点
Java只支持单继承,不支持多继承。
//一个类只能有一个父类,不可以有多个父类。
class C extends A{} //ok
class C extends A,B... //error
Java支持多层继承(继承体系)。
class A{}
class B extends A{}
class C extends B{}
顶层父类是Object类。所有的类默认继承Object,作为父类。
子类和父类是一种相对的概念。例如:B类对于A来说是子类,但是对于C类来说是父类
一个父类可以同时拥有多个子类
方法重写
我们说父类的所有方法子类都会继承,但是当某个方法被继承到子类之后,子类觉得父类原来的实现不适合于子类,该怎么办呢?我们可以进行方法重写 (Override)。子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
class Phone {
public void sendMessage(){
System.out.println("发短信");
}
public void call(){
System.out.println("打电话");
}
public void showNum(){
System.out.println("来电显示号码");
}
}
//智能手机类
class NewPhone extends Phone {
//重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能
public void showNum(){
//调用父类已经存在的功能使用super
super.showNum();
//增加自己特有显示姓名和图片功能
System.out.println("显示来电姓名");
System.out.println("显示头像");
}
}
public class ExtendsDemo06 {
public static void main(String[] args) {
// 创建子类对象
NewPhone np = new NewPhone();
// 调用父类继承而来的方法
np.call();
// 调用子类重写的方法
np.showNum();
}
}
重写的注意事项
- 方法重写是发生在子父类之间的关系。
- 子类方法重写父类方法,返回值类型、方法名和参数列表都要一模一样。
- 子类方法重写父类方法,必须要保证访问权限大于等于父类权限。访问权限从大到小: public protected (默认) private
- 子类方法的返回值类型必须【小于等于】父类方法的返回值类型(小于其实就是是它的子类,例如:Student < Person)。如果返回值类型是基本数据类型和void,那么必须是相同
- 使用@Override注解,检验是否重写成功,重写注解校验!建议重写方法都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!
- 静态方法不能被重写丶私有等在子类中不可见的方法不能被重写丶final方法不能被重写
- this:存储的“当前对象”的引用。this可以访问:本类的成员属性、成员方法、构造方法;
- super:存储的“父类对象”的引用。super可以访问:父类的成员属性、成员方法、构造方法;
this关键字的三种用法
this访问本类成员变量: this.成员变量
public class Student{
String name = "张三";
public void show(){
String name = "李四";
System.out.println("name = " + name);// 李四
System.out.println("name = " + this.name);// 张三
}
}
this访问本类成员方法: this.成员方法名();
public class Student{
public void show(){
System.out.println("show方法...");
this.eat();
}
public void eat(){
System.out.println("eat方法...");
}
}
this访问本类构造方法: this( )可以在本类的一个构造方法中,调用另一个构造方法
public class Student{
public Student(){
System.out.println("空参构造方法...");
}
public Student(String name) {
this();//当使用this()调用另一个构造方法时,此代码必须是此构造方法的第一句有效代码。
System.out.println("有参构造方法...");
}
}
public class Demo {
public static void main(String[] args) {
Student stu2 = new Student();
}
}
super关键字的三种用法
-
super访问父类的成员变量: super.父类成员变量名
class Fu{
int num = 100;
}
class Zi extends Fu{
int num = 10;
public void show(){
int num = 1;
System.out.println("局部变量num:"+num);// 1
System.out.println("Zi 类中的num:"+this.num);// 10
System.out.println("Fu 类中的num:"+super.num);// 100
}
}
super访问父类的成员方法: super.成员方法名();
class Fu{
public void method1(){
System.out.println("Fu method1...");
}
}
class Zi extends Fu{
public void show(){
// 访问父类的method1方法
super.method1();
}
@Override
public void method1(){
super.method1();// 调用父类的method1方法
System.out.println("Zi method1...");
}
}
super访问父类的构造方法: super( )
class Fu {
public Fu() {
System.out.println("Fu 类的空参构造方法..");
}
public Fu(String name, int age) {
System.out.println("Fu 类的有参构造方法..");
}
}
class Zi extends Fu {
public Zi() {
super();// 调用父类的空参构造方法
System.out.println("Zi 类的空参构造方法..");
}
public Zi(String name, int age) {
super(name, age);// 调用父类的有参构造方法
System.out.println("Zi 类的有参构造方法..");
}
}
public class Demo {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println("----------------------");
Zi z2 = new Zi("刘德华", 17);
}
}
注意事项
- super访问成员变量和成员方法: 优先去父类中找,如果有就直接使用,如果没有就去爷爷类中找,如果有,就用,依次类推...
- 子类的构造方法默认会调用父类的空参构造方法,如果父类中的没有空参构造方法,只定义了有参构造方法,会编译报错
- 子类构造方法中使用super调用父类的构造方法,是为了在创建子类对象的时候,初始化从父类继承过来的属性
- 在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。
- this(…)super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存
使用abstract关键字修饰的类就是抽象类。这种类不能被创建对象,它就是用来做父类的,被子类继承的。
语法:
抽象方法的概述
- 没有方法体,使用abstract修饰的方法就是抽象方法
语法:
作用: 强制要求子类重写的方法可以定义为抽象方法
代码示例
abstract class Animal {
// 成员变量
private String name;
private int age;
// 构造方法
public Animal(){
}
public Animal(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;
}
// 所有子类显示信息的方法实现都是一样的
public void show(){
System.out.println(name+","+age);
}
// 抽象方法 ---
// 因为所有子类吃东西的方法实现不一样
public abstract void eat();
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头...");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼...");
}
}
public class Test {
public static void main(String[] args) {
Dog d = new Dog();
d.eat();
Cat c = new Cat();
c.eat();
}
}
抽象类的注意事项
关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。
-
抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
-
抽象类中,也有构造方法,是供子类创建对象时,初始化父类成员变量使用的。
理解:子类的构造方法中,有默认的super()或手动的super(实参列表),需要访问父类构造方法。
-
抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
-
抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。
- 设计模式就是解决一些问题时的固定思路,也就是代码设计思路经验的总结。 模板设计模式概述:针对某些情况,在父类中指定一个模板,然后根据具体情况,在子类中灵活的具体实现该模板
抽象类体现的就是模板设计思想
- 模板是将通用的东西在抽象类中具体的实现,而模板中不能决定的东西定义成抽象方法,让使用模板(继承抽象类的类)的类去重写抽象方法实现需求。
模板模式的实现步骤
- 定义抽象父类作为模板
- 在父类中定义"模板方法"--- 实现方法(通用模板)+抽象方法(填充模板)
- 子类继承父类,重写抽象方法(填充父类的模板)
- 测试类中创建子类对象,通过子类调用父类的“实现的方法”+ “子类重写后的方法”
代码示例
// 父类
abstract class Driver {
// 开车方法 通用模板
public void driveCar() {
System.out.println("开门");
System.out.println("点火");
// 姿势??
ziShi();
System.out.println("刹车");
System.out.println("熄火");
}
// 姿势方法 填充模板
public abstract void ziShi();
}
//现在定义两个使用模板的司机:
//新司机
class NewDriver extends Driver {
@Override
public void ziShi() {
System.out.println("双手紧握方向盘");
}
}
//老司机
class OldDriver extends Driver {
@Override
public void ziShi() {
System.out.println("右手握方向盘左手抽烟");
}
}
public class Test {
public static void main(String[] args) {
// 创建新司机对象
NewDriver d1 = new NewDriver();
d1.driveCar();
// 创建老司机对象
OldDriver d2 = new OldDriver();
d2.driveCar();
}
}
可以看出,模板模式的优势是,模板已经定义了通用架构,使用者只需要关心自己需要实现的功能即可!非常的强大!
final关键字概述: final关键字表示不可改变。可以用于修饰类、方法和变量。
修饰类:表示这个类不能被继承,没有子类
查询API发现像 public final class String 、public final class Math 、public final class Scanner 等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。
代码示例
final class Eunuch{//太监类
}
class Son extends Eunuch{//错误
}
修饰方法:表示这个方法不能被子类重写
代码示例
class Father{
public final void method(){
System.out.println("father");
}
}
class Son extends Father{
public void method(){//错误
System.out.println("son");
}
}
修饰变量
基本类型的局部变量:被final修饰后,只能赋值一次,不能再更改。代码如下:
public class FinalDemo1 {
public static void main(String[] args) {
// final修饰基本数据类型
final int NUM = 10;
// NUM = 20;// 编译报错,final修饰的变量只能赋值一次,不能重复赋值
}
}
引用类型的局部变量:被final修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改,代码如下:
public class FinalDemo2 {
public static void main(String[] args) {
// 引用类型
final Student stu = new Student("张三", 18);
//stu = new Student("李四",19);// 编译报错
stu.setAge(19);
}
}
成员变量
成员变量涉及到初始化的问题,初始化方式有两种,只能二选一:
显示初始化;
public class FinalVariable {
final int NUM1 = 10;
}
构造方法初始化
public class FinalVariable {
final int NUM2;
public FinalVariable(int NUM2) {
this.NUM2 = NUM2;
}
public FinalVariable() {
this.NUM2 = 10;
}
}
被final修饰的常量名称,一般都有书写规范,所有字母都大写。



