工程和模块:
# 1.工程 1)在企业开发中创建工程(项目project) # 2.模块 1) 在一个空的工程中可以创建多个模块 2)好处:方便管理,我们不做大的项目之前可以每天创建一个模块 3) 弊端:就是一个模块中报错其他模块不能运行 锁哥课程中采用创建每天一个工程。
修饰符 class 类名{
// 类中的五大成分。之前学习三个成分
// 1.成员变量(属性)
// 2.成员方法 (行为)
// 3.构造器 (初始化类的对象数据的)
}
类名 对象名称 = new 类名();
一、封装:
- 使用 private 关键字来修饰成员变量。
- 使用public修饰getter和setter方法。 ```java
public class Student { private String name; private int age;
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
<a name="XH0KW"></a>
## 构造器:
<a name="OxLXx"></a>
### 构造器的作用:
> 通过调用构造器可以返回一个类的对象,构造器同时负责帮我们把对象的数据(属性和行为等信息)初始化。
```java
修饰符 类名(形参列表) { // 构造体代码,执行代码 }
this关键字的作用:
1、this代表所在类的当前对象的引用(地址值),即代表当前对象。 2、this出现在实例方法中,谁调用这个方法(哪个对象调用这个方法),this就代表谁(this就代表哪个对象)。
匿名对象:
new 类名(参数列表);
注意:匿名对象通常是在对象只需要访问成员一次的情况下使用
如果对象需要多次的操作成员,就不能使用匿名对象来访问。
二、 继承
继承:就是子类继承父类的属性和行为,使得子类对象可以直接具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
classs 类1 extends 类2
{
//代码
}
继承的好处:
class C extends A{} //ok
class C extends A,B... //error
- Java支持多重继承(继承体系)。
class A{}
class B extends A{}
class C extends B{}
方法重写:
方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
1)旧手机功能:基本的打电话,发信息
2)新手功功能:基本的打电话下支持视频通话,基本的发信息下支持发送语音和图片。
定义旧手机类,实现打电话,发信息功能。定义新手机类继承老手机,重写打电话和发信息功能。
package com.itheima.sh.d_extends_04;//1.定义一个旧手机类public class OldPhone { //2.在旧手机类中定义打电话 public void call(){ System.out.println("旧手机只能打电话"); } //和发短信功能 public void sendMessage(){ System.out.println("旧手机只能发短信"); }}package com.itheima.sh.d_extends_04;// 3.定义一个新手机类继承旧手机public class NewPhone extends OldPhone{ //4.在子类即新手机类中对旧手机的打电话和发短信功能进行重写即重新编写 //书写要重写的方法名回车 @Override public void call() { //调用的是父类的功能 super.call(); System.out.println("新手机除了打电话还可以视频通话"); } @Override public void sendMessage() { //调用的是父类的功能 super.sendMessage(); System.out.println("新手机除了发短信还可以发图片"); }}package com.itheima.sh.d_extends_04;/* 步骤: 1.定义一个旧手机类 2.在旧手机类中定义打电话和发短信功能 3.定义一个新手机类继承旧手机 4.在子类即新手机类中对旧手机的打电话和发短信功能进行重写即重新编写 5.在测试类中创建子类对象,使用对象调用方法 */public class Test01 { public static void main(String[] args) { //5.在测试类中创建子类对象,使用对象调用方法 NewPhone np = new NewPhone(); np.call(); np.sendMessage(); }}
@Override重写注解
- Override:注解,重写注解校验!
- 这个注解标记的方法,就说明这个方法必须是重写父类的方法,否则编译阶段报错。
- 建议重写都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!
注意事项
- 方法重写是发生在子父类之间的关系。
- 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
- 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
继承后的特点—构造器
引入
- 构造器的名字是与类名一致的。所以子类是无法继承父类构造方法的。
- 构造器的作用是初始化对象成员变量数据的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。(先有爸爸,才能有儿子)
需求:
根据以下代码画图说明子父类构造函数的特点。
1)创建一个子类Zi和一个父类Fu,让这个子类来继承这个Fu类;
2)在Fu类中定义一个成员变量x并赋值为3,然后创建Fu类构造代码块,在这个Fu类代码块中打印x的值;
3)在Fu类中定义一个一般函数show,也打印x的值;
4)在Fu类中定义一个无参构造函数,随便打印一句话;
5)在Zi类中定义一个成员变量y并赋值为10,同样定义一个构造代码块,分别写两个打印语句打印x和y的值;
6)在子类中复写父类中show函数,并写两句语句,分别打印x和y的值;
7)在子类中定义一个构造函数,使用super()调用父类无参构造函数,在子类构造函数中打印一句话,调用show函数;
8)定义一个测试类ConstructorDemo ,在这个类中创建Zi类的对象;
//继承中的构造函数细节
class Fu
{
int x = 3;
{
System.out.println("Fu 构造代码块 x="+x);
}
Fu()
{
//super();
System.out.println("Fu的构造函数执行");
}
void show()
{
System.out.println("Fu show x="+x);
}
}
class Zi extends Fu
{
int y = 10;
{
System.out.println("Zi 的构造代码块 x="+x);
System.out.println("Zi 的构造代码块 y="+y);
}
Zi()
{
super();
System.out.println("Zi的构造函数执行。。。。。");
show();
}
void show()
{
System.out.println("Zi show x="+x);
System.out.println("Zi show y="+y);
}
}
class ConstructorDemo
{
public static void main(String[] args)
{
Zi z = new Zi();
}
}
super(…)和this(…)
super和this的用法格式:
this.成员变量 — 本类的 super.成员变量 — 父类的
this.成员方法名() — 本类的
super.成员方法名() — 父类的
class Person {
private String name ="凤姐";
private int age = 20;
public Person() {
System.out.println("父类无参");
}
public Person(String name , int age){
this.name = name ;
this.age = age ;
}
// getter/setter省略
}
class Student extends Person {
private double score = 100;
public Student() {
//super(); // 调用父类无参构造器,默认就存在,可以不写,必须再第一行
System.out.println("子类无参");
}
public Student(String name , int age,double score) {
super(name ,age);// 调用父类有参构造器Person(String name , int age)初始化name和age
this.score = score;
System.out.println("子类有参");
}
// getter/setter省略
}
public class Demo07 {
public static void main(String[] args) {
// 调用子类有参数构造器
Student s2 = new Student("张三",20,99);
System.out.println(s2.getScore()); // 99
System.out.println(s2.getName()); // 输出 张三
System.out.println(s2.getAge()); // 输出 20
}
}
注意
子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。**super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。**
super(..)是根据参数去确定调用父类哪个构造器的。
super(…)案例图解
父类空间优先于子类对象产生 在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造器调用时,一定先调用父类的构造器。理解图解如下:
this(…)用法演示
this(…)
- 默认是去找本类中的其他构造器,根据参数来确定具体调用哪一个构造器。
为了借用其他构造器的功能。 ```java package com.itheima._08this和super调用构造器; class Student{ private String name ; private int age ; private char sex ;
public Student() { // 很弱,我的兄弟很牛逼啊,我可以调用其他构造器:Student(String name, int age, char sex)
this("徐干",21,'男');
}
public Student(String name, int age, char sex) {
this.name = name ;
this.age = age ;
this.sex = sex ;
}
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 char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
} }
/**
- this(…):
- 默认是去找本类中的其他构造器,根据参数来确定具体调用哪一个构造器。
- 为了借用其他构造器的功能。 / public class ThisDemo01 { public static void main(String[] args) { Student xuGan = new Student(); System.out.println(xuGan.getName()); // 输出:徐干 System.out.println(xuGan.getAge());// 输出:21 System.out.println(xuGan.getSex());// 输出: 男 } }
```java
- 子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。
- super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。
- super(..)和this(...)是根据参数去确定调用父类哪个构造器的。
- super(..)可以调用父类构造器初始化继承自父类的成员变量的数据。
- this(..)可以调用本类中的其他构造器。
三、抽象类:
使用某个类描述事物的时候,如果这个类中在描述这个事物的某个行为或功能的时候,只知道这个事物有这个行为或功能,但没有办法书写清楚具体的功能体,函数体,这时可以使用抽象函数来表示这个行为或功能,由于类中有抽象的函数,这个类就会变成抽象类。
注意事项
1、子类在继承抽象类后,需要把抽象类中所有的抽象方法全部复写(重写)完成。抽象类中定义所有子类的共性行为,然后由具体的子类针对自己的实际情况复写父类提供的基本行为,建立适合自己的功能体。
2、抽象类和一般类有什么区别?
抽象类肯定需要abstract修饰,一般类不能使用。
不管是抽象类,还是一般类,它们都是描述事物体系中的某个事物,只不过抽象类描述的一定是这个事物体系中的共性内容,抽象类不一定是最顶层的类,但一定不是最底层的类。
3、抽象类有没有构造函数,能不能创建对象?
有构造函数,但不能创建对象。
构造函数是给成员变量初始化的,抽象类中的构造函数就是为了子类对象初始化使用的,因为抽象类一定有子类,而创建子类对象的时候,在子类的构造函数中一定有super()语句会找自己的父类构造函数进行初始化动作。
1)定义一个抽象类Animal作为父类,在这个父类中定义一个带有一个参数的构造函数,接收子类传递过来的值,并打印;
2)在抽象类Animal中定义一个抽象函数eat;
3)再定义一个Cat猫类,让这个猫类继承Animal类,在这个Cat类中定义一个构造函数,在构造函数中使用super调用Animal中的构造函数;
4)在类Cat中复写eat函数;
5)定义一个测试抽象类,并在这个类中创建Cat的对象;
abstract class Animal
{
Animal(int b)//抽象类中的有参构造函数
{
System.out.println(b);
}
abstract void eat();
}
class Cat extends Animal
{
Cat()
{
super(3);
}
void eat(){}
}
class AbstractDemo
{
public static void main(String[] args)
{
Cat c=new Cat();
}
}
演示抽象类不能实例化,也就是说抽象类不能创建对象。
抽象类一定是个类,类中肯定就会有构造函数。抽象类不能创建对象的原因是抽象类中有抽象函数,如果我们可以直接创建抽象类的对象,那么就可以使用这个对象调用那个抽象函数,而抽象函数是没有函数体的函数,调用函数的最终目的是需要函数体的执行,完成我们想要的结果。因此我们如果可以创建抽象类的对象,那么就会导致可以调用抽象函数,而调用了抽象函数,却得不到任何想要的效果。这样的做法没有意义。因此sun公司在指定抽象类的规则时,不让程序直接创建抽象类的对象。
4、抽象类一定是父类吗?
一定是父类,一定不是顶层父类。
抽象类中通常都有抽象函数,而抽象类中的抽象函数要求必须由子类来复写(由具体的子类来实现其中的函数体)。
子类的主要作用是复写抽象类中的抽象函数。
5、抽象类可以继承其他类吗?
抽象类也是一个类,因此它必须具备类的继承特点。它可以有父类。
6、抽象关键字不能和哪些关键字共存?
private修饰符:表示私有的。
private :父类中私有的成员,子类是不知道的,因此使用private 和abstract关键字一起修饰函数,导致子类根本无法知道父类中有个抽象函数,同时也导致了子类不能复写父类中的方法。
static修饰符:表示静态的。
static:如果使用static和abstract关键字一起修饰抽象函数,导致这个函数可以使用类名直接调用,而抽象函数是没有方法体的,调用这个抽象函数是没有意义的。
final修饰符:表示最终的。(先了解)
final :final修饰的函数子类是无法复写的,而abstract修饰的函数,要求子类必须复写。
抽象类何时使用:
当描述事物体系,一般在描述所有体系中最共性的内容时,通常是只知道体系的共性功能,却不能书写具体功能体,这时会使用抽象函数表示,那么这个类一定会使用抽象类表示。
抽象类存在的意义
抽象类:在描述事物的时候,没有足够的信息描述一个事物,这时该事物就是抽象事物。抽象类存在的意义和我们之前学过的父类存在思想是一样的,那么有父类到底有什么好处呢?父类有抽象和非抽象的,但是都一样,父类或抽象类的存在让我们面对事物发生了改变,我们不要再去面对具体的子类事物,直接面对父类就可以了。
将类定义为抽象类时,这样别人看到你的代码,或你看到别人的代码,你就会注意抽象方法,而知道这个方法是在子类中实现的,所以,有个提示作用。(子类一定要复写父类中的抽象方法)
举例:问你个问题,你知道什么是“东西”吗?什么是“物体”吗?
“麻烦你,小黑。帮我把那个东西拿过来好吗”
在生活中,你肯定用过这个词--东西。
小黑:“你要让我帮你拿那个水杯吗?”
你要的是水杯类的对象。而东西是水杯的父类。通常东西类没有实例对象,但我们有时需要东西的引用指向它的子类实例。
总结:抽象类存在的意义是为了被子类继承,否则抽象类将毫无意义,抽象类体现的是模板思想,模板是通用的东西。模板中不能决定的东西定义成抽象方法,让使用模板(继承抽象类的类)的类去重写抽象方法实现需求,这是典型的模板思想。