编写车Vehicle的父类,属性:车牌号、品牌 方法:计算总租金 public int getSumRent(int days){ return 100; }
package com.jian.demo1;
public class Vehicle {
//编写实例变量
String id;
String brand;
public Vehicle() {
}
public Vehicle(String id, String brand) {
this.id = id;
this.brand = brand;
}
//方法:计算总租金
public int getSumRent(int days){
//注意:不同车的总租金不一样,也就是需要在子类中重写,因此父类的总租金方法体可以编写任意一个int类型的值返回
return 0;
}
public void print(){
System.out.println("OK");
}
}
编写大巴车子类 继承车的父类 独有属性:座位 座位数<16,400元 座位数>=16,600元 重写父类的总租金方法
package com.jian.demo1;
public class Bus extends Vehicle {
//编写独有实例变量
int seat;
public Bus() {
}
public Bus(String id, String brand, int seat) {
super(id, brand);
this.seat = seat;
}
@Override
public int getSumRent(int days) {
/*
总租金 = 日租金 * 租的总天数
但是日租金要根据实例变量座位数进行判断得到
*/
if(this.seat < 16){
return 400 * days;
}
return 600 * days;
}
}
编写小轿车子类 继承车的父类 独有的属性:车型(两厢、三厢、越野) 两厢300元、三厢350元、越野500元 重写父类的总租金方法
package com.jian.demo1;
public class Car extends Vehicle {
//编写独有实例变量
String type;
public Car() {
}
public Car(String id, String brand, String type) {
super(id, brand);
this.type = type;
}
@Override
public int getSumRent(int days) {
/*
总租金 = 日租金 * 租的总的天数
但是日租金要根据实例变量车型判断得到
*/
if("两厢".equals(this.type)){
return 300 * days;
}else if("三厢".equals(this.type)){
return 350 * days;
}else{
return 500 * days;
}
}
}
编写测试类
package com.jian.demo1;
public class Test {
public static void main(String[] args) {
/*
多态的语法格式:
父类类型 对象名 = new 子类();
注意:当构成多态时,对象名是父类类型,因此只能访问父类中的实例变量和父类的实例方法,但是优先访问子类重写以后的方法
*/
Vehicle c = new Car(); //构成多态
System.out.println(c.id);
System.out.println(c.brand);
// System.out.println(c.type); //出现编译错误,原因:当前对象名c是父类类型,父类中没有车型实例变量,因此就出现编译错误
c.print();
System.out.println("总租金:" + c.getSumRent(1)); //输出500,原因:当构成多态以后,会优先调用当前子类对象中重写以后的方法
}
}
package com.bjpowernode.demo1;
public class Test2 {
public static void main(String[] args) {
// Car c = new Car(); //不报错,但是没有构成多态
Vehicle v = new Bus(); //构成多态
System.out.println("总租金:" + v.getSumRent(1)); //400
v = new Car(); //构成多态
System.out.println("总租金:" + v.getSumRent(1)); //500
/*
通过运行得到:
1.多态定义:
多个对象调用同一个方法,得到多个不同的结果,原因:构成多态后,优先调用子类重写以后的方法
多种不同的形态(结果)
在现实生活中多态案例,比如:理发师、裁缝、医生.....都使用剪刀,得到不一样的结果 2.满足多态的条件:
子类继承父类
必须在子类中重写父类的方法
父类类型 对象名 = new 子类();
*/
}
}
宠物Pet类 方法:吃
package com.jian.demo2;
public class Pet {
//编写方法:吃
public void eat(){
System.out.println("正在吃.......");
}
}
编写子类
package com.jian.demo2;
public class Dog extends Pet {
@Override
public void eat() {
System.out.println("小狗正在吃狗粮....");
}
}
package com.jian.demo2;
public class Cat extends Pet {
@Override
public void eat() {
System.out.println("小猫正在吃鱼......");
}
}
package com.jian.demo2;
public class Bird extends Pet {
@Override
public void eat() {
System.out.println("小鸟正在吃虫子.....");
}
}
编写主人类 方法:喂养feed猫
package com.jian.demo2;
public class Master { //编写主人类
//编写方法:喂养feed猫
/*public void feed(Cat cat){
cat.eat();
}
public void feed(Dog dog){
dog.eat();
}*/
/*
可是宠物有很多,也就是说有多个具体的宠物,则就需要在主人类中编写多个喂养的方法,但是比较麻烦
其实以上两个喂养方法中的形参猫和狗都是从宠物继承过来的,因此能否编写主人喂养宠物这一个方法
*/
public void feed(Pet pet){
pet.eat();
}
}
编写测试类
package com.jian.demo2;
public class Test {
public static void main(String[] args) {
//创建主人对象
Master master = new Master();
//调用主人的喂养方法
master.feed(new Cat());
master.feed(new Dog());
master.feed(new Bird());
}
}
人类: 属性:姓名,性别、年龄 方法:自我介绍的方法
package com.jian.demo3;
public class Person {
//编写实例变量
String name;
char gender;
int age;
public Person() {
}
public Person(String name, char gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
//编写方法:自我介绍
public void print(){
System.out.print("大家好,我叫" + name + ",今年" + age + "岁了,性别是" + gender);
}
}
学生类 继承 人类 独有属性:学号 独有方法:学习 重写父类的自我介绍
package com.jian.demo3;
public class Student extends Person {
//独有实例变量:学号
String id;
public Student() {
}
public Student(String name, char gender, int age, String id) {
super(name, gender, age);
this.id = id;
}
//编写方法:学习
public void study(){
System.out.println("正在学习面向对象......");
}
@Override
public void print() {
super.print();
System.out.println(",学号是" + id);
}
}
教师类 继承人类 独有属性:薪资 独有方法:教学 重写父类的自我介绍方法
package com.jian.demo3;
public class Teacher extends Person {
//独有薪资
double salary;
public Teacher() {
}
public Teacher(String name, char gender, int age, double salary) {
super(name, gender, age);
this.salary = salary;
}
//编写独有方法:教学
public void teach(){
System.out.println("正在教面向对象......");
}
@Override
public void print() {
super.print();
System.out.println(",薪资是" + this.salary);
}
}
多态中的向上转型,也叫做自动类型转换
package com.jian.demo3;
public class Test {
public static void main(String[] args) {
Person person = new Student(); //构成多态也就是向上转型或者叫做自动类型转换,注意:只能访问父类中的实例变量和父类中的实例方法,但是优先访问子类重写以后的方法
System.out.println(person.name);
System.out.println(person.age);
System.out.println(person.gender);
// System.out.println(person.id); //出现编译错误,原因:当前对象名是父类类型,不能访问子类独有的,因此就出现编译错误
person.print();
}
}
多态中的向下转型也叫做强制类型转换
package com.jian.demo3;
public class Test2 {
public static void main(String[] args) {
Person p = new Student(); //构成多态,也叫做向上转换或者叫做自动类型转换
/*
实现输出:当是学生对象输出学号,当是教师对象输出薪资
但是出现编译错误
原因:当构成多态时,不能直接访问子类独有的实例变量或实例方法
解决办法:将p强制转为学生类型,然后再访问子类学生中的学号实例变量
*/
// System.out.println("学号:" + p.id);
// int a = (int)3.15; //强制类型转换
Student stu = (Student) p; //强制类型转换,也叫做向下转换,其实由父到子
System.out.println("学号:" + stu.id);
/*
出现运行错误java.lang.ClassCastException类型转换异常
原因:当前对象名p中存放的是学生对象,也就是说不能随便转为其他子类类型,否则出现类型转换异常
解决办法:在进行向下转型或者强制类型转换之前先进行判断,如果当前对象名中存放的是该对象,则再进行向下转换或者强制类型转换,则使用instanceof关键字
*/
/* Teacher t = (Teacher)p;
System.out.println("薪资:" + t.salary);*/
}
}
多态中的向下转型也叫做强制类型转换,使用instanceof关键字
package com.jian.demo3;
public class Test3 {
public static void main(String[] args) {
Person p = new Student(); //构成多态也就是向上转型也叫做自动类型转换
//p = new Teacher("张三", '男', 20, 5000);
/*
实现功能:
当前对象名中存放的是学生对象,则输出学生的独有属性学号和学生的独有方法学习
当前对象名中存放的是教师对象,则输出教师独有属性薪资和调用独有方法教学
建议:在进行向下转型或者强制类型转换之前,先判断,则使用instanceof关键字
*/
if(p instanceof Student){
//表示当前对象名p中存放的是学生对象,则就可以转为学生类型
/*Student s = (Student)p; //向下转换也叫做强制类型转换
System.out.println("学号:" + s.id);
s.study();*/
//其实上面三条语句也可以编写为如下代码
System.out.println("学号:" + ((Student) p).id);
((Student) p).study();
}else if(p instanceof Teacher){
//表示当前对象名p中存放地点是教师对象,则就可以转为教师类型
Teacher t = (Teacher)p; //向下转换也叫做强制类型转换
System.out.println("薪资:" + t.salary);
t.teach();
}
}
}
package com.jian.demo3;
public class Test4 {
public static void main(String[] args) {
Student stu = new Student(); //没有构成多态,不报错
/*
注意:当前对象名stu是学生类型,在访问实例变量或实例方法时,先在学生类中找,如果找不到则再去父类中找
也就得到结论:如果对象名是子类类型,既可以访问子类中的实例变量和实例方法,也可以访问父类中的实例变量和实例方法
*/
System.out.println("姓名:" + stu.name);
System.out.println("学号:" + stu.id);
stu.print();
stu.study();
Person stu2 = new Student(); //构成多态,也就是向上转型或者自动类型转换
/*
注意:当前对象名stu2是父类类型,只能访问父类中的实例变量和实例方法,但是优先访问子类重写以后的方法
如果构成多态,非要访问子类独有的实例变量或实例方法,则必须进行向下转型也叫做强制类型转换
*/
}
}
修改租车租金测试类
package com.jian.demo4;
import java.util.Scanner;
/**
* 测试类使用多态完成计算总租金,并且优化代码,调用总租金方法编写在switch外面,建议先判断否则可能会出现空指针异常
*
*/
public class Test2 {
public static void main(String[] args) {
//根据选择不同的车来计算不同车的租金
//第一步:键盘输入要选择租赁的车
Scanner input = new Scanner(System.in);
System.out.println("请选择要租赁的车:(1.Car 2.Bus)");
int num = input.nextInt();
//第二步:根据输入num中的值创建对象,并且计算总租金
Vehicle v = null;
switch (num){
case 1: //表示Car
//创建小轿车对象
v = new Car(); //构成多态,也叫做向上转型或者叫做自动类型转换
break;
case 2: //表示Bus
//创建大巴车对象
v = new Bus(); //构成多态,也叫做向上转型或者叫做自动类型转换
break;
default:
System.out.println("输入编号有误!");
}
//建议:在调用总租金方法之前,先判断,如果当前对象名v不等于null则在调用总租金方法,否则可能回车空指针异常
if(v != null){
System.out.println("总租金:" + v.getSumRent(1)); //优先调用子类重写以后的方法
}
}
}
package com.jian.demo4;
import java.util.Scanner;
/**
* 将根据编号创建对象抽取方法完成
*
*/
public class Test3 {
public static void main(String[] args) {
//根据选择不同的车来计算不同车的租金
//第一步:键盘输入要选择租赁的车
Scanner input = new Scanner(System.in);
System.out.println("请选择要租赁的车:(1.Car 2.Bus)");
int num = input.nextInt();
//第二步:根据输入num中的值创建对象,并且计算总租金
Vehicle v = getVehicle(num);
//建议:在调用总租金方法之前,先判断,如果当前对象名v不等于null则在调用总租金方法,否则可能回车空指针异常
if(v != null){
System.out.println("总租金:" + v.getSumRent(1)); //优先调用子类重写以后的方法
}
}
public static Vehicle getVehicle(int num) {
Vehicle v = null;
switch (num){
case 1: //表示Car
//创建小轿车对象
v = new Car(); //构成多态,也叫做向上转型或者叫做自动类型转换
break;
case 2: //表示Bus
//创建大巴车对象
v = new Bus(); //构成多态,也叫做向上转型或者叫做自动类型转换
break;
default:
System.out.println("输入编号有误!");
}
return v;
}
}
1.static关键字可以修饰属性
package com.jian.demo5;
/**
* 1.static关键字可以修饰属性
* 1.1在类中声明的变量,称为属性也叫做成员变量或者字段field
* 如果属性(成员变量或者字段)没有使用static关键字修饰,称为实例变量,也就是对象变量
* 如果属性(成员变量或者字段)使用static关键字修饰,称为静态变量,也就是类的变量
* 1.2静态变量的特点:
* 1.2.1当类加载到内存时,则就给静态变量分配空间,一直到程序结束
* 1.2.2静态变量在方法区中存储
* 1.2.3静态变量不属于某个对象,而是整个类中的所有对象都可以共享
* 因此可以使用:类名.静态变量名
* 也可以使用:对象名.静态变量名
* 即使对象名的值为null时,也可以访问静态变量,不会出现空指针异常,原因:静态变量当类加载内存时就在方法区中存在,一直到程序结束
* 1.2.4类优先于对象,也就是说类的生命周期比较长
* 1.3静态变量使用场景:
* 当多个对象中的某个属性值都一样时,则就可以编写为静态变量,原因:在方法区中只存放一次,也就是说节省空间
*
*/
public class MyClass {
int x; //实例变量也就是对象变量
static int y; //静态变量也叫做类的变量
static String address = "北京市";
}
package com.jian.demo5;
public class Test {
public static void main(String[] args) {
/*
注意:1.当使用MyClass类,则就将MyClass.class字节码文件加载到内存,同时在方法区中给静态变量y分配空间,并且y的值为0
注意:2.因此使用类名可以访问静态变量名
*/
System.out.println(MyClass.y); //0
// System.out.println(MyClass.x); //出现编译错误,原因:当前x是实例变量,也就是说目前还没有创建对象,实例变量x还不存在
//注意:目前还没有创建对象,也就是说对象以及实例变量和实例方法都不存在
/*
假如创建MyClass对象
当执行new运算符,则表示在堆内存中创建一个对象,并且开辟一块空间进行存储,并且该对象中存放实例变量x,x的值为默认值0
则就可以使用:对象名.实例变量名
也可以使用对象名.静态变量名 原因:静态变量一直到程序结束,也就是说如果程序还没有结束,则静态变量就一直存在
*/
MyClass m = new MyClass();
System.out.println(m.x); //0
System.out.println(m.y); //0
/*
假如对象使用完毕,则就变为垃圾回收
同时该对象中的实例变量也随之释放,也就是实例变量x不存在
也就是说,如果对象名的值为null时,则就不能访问对象中的实例变量或实例方法,否则出现空指针异常
*/
m = null;
// System.out.println("m.x = " + m.x);
System.out.println("m.y = " + m.y); //0
}
}
2.static关键字可以修饰方法
package com.jian.demo6;
/**
* 2.static关键字可以修饰方法
* 2.1如果使用static关键字修饰方法,称为静态方法也叫做类的方法
* 如果没有使用static关键字修饰方法,称为实例方法也叫做对象的方法、非静态方法
* 2.2静态方法中可以使用静态变量和静态方法
* 实例方法中可以使用静态变量和静态方法,还可以使用实例变量和实例方法
* 原因:类优先于对象
* 2.3其实main方法也是静态方法
* 2.4静态方法使用的场景:
* 1.一般编写工具类中的工具方法时,该方法编写为静态方法
* 比如:Math.pow(2,3)
* 2.一般方法体中没有使用到实例变量和实例方法时,则就可以编写为静态方法
*
*/
public class MyClass {
int x; //实例变量
static int y; //静态变量
//编写实例方法
public void print(){
y = 11;
show();
x = 22;
print2();
}
public void print2(){
}
//编写静态方法
public static void show(){
}
public static void show2(){
y = 100;
show();
/*x = 200; //出现编译错误,原因:x是实例变量
print(); //出现编译错误,原因:print是实例变量*/
}
}
package com.jian.demo6;
public class Test {
public static void main(String[] args) {
Test.print();
//上面一条语句也可以编写为如下
print(); //注意:同一个类中的静态方法可以直接访问,默认有当前类的类名.
//其实还可以编写为:
/*Test t = new Test();
t.print(); //静态方法一般使用类名.使用更多*/
//上面两条语句也可以编写为
new Test().print();
}
private static void print() {
for(int i = 1;i <= 5;i++){
System.out.println(i);
}
}
}
3.static关键字可以修饰代码块
package com.jian.demo7;
/**
* 3.static关键字可以修饰代码块
* 3.1使用static关键字修饰的代码块,称为静态代码块
* 3.2静态代码块语法格式
* static{
*
* }
* 3.3静态代码块的作用
* 完成对静态变量赋值
* 3.4静态代码块如何执行?
* 当类加载到内存时执行静态代码块,并且只执行一次
*
*/
public class MyClass {
int x; //实例变量
static int y = 100; //静态变量
static int z; //静态变量
//静态代码块
static {
z = 200;
System.out.println("执行了静态代码块......");
}
//构造方法:完成对实例变量赋值
public MyClass() {
System.out.println("执行了无参构造方法.....");
}
public MyClass(int x) {
this.x = x;
System.out.println("执行了带一个参数的构造方法.....");
}
}
package com.jian.demo7;
public class Test {
public static void main(String[] args) {
/*
创建MyClass对象执行过程分析:
1.先将MyClass.class字节码文件加载到内存中
2.然后在方法区中开辟空间存储静态变量y和z,并且y的值为100,z的值为默认值0
3.然后再执行静态代码块,完成对静态变量z赋值,z = 200
4.执行new运算符,表示创建一个对象,并且在堆内存中开辟一块空间存储一个对象,并且该对象中存放一个实例变量x,x的值为默认值0
5.同时执行相匹配的构造方法,也就是执行带一个参数的构造方法,完成对实例变量x赋值,x = 123
6.将对象的内存地址赋给左侧的对象名m,也就是m中存放的是地址
*/
MyClass m = new MyClass(123);
m = new MyClass();
MyClass m2 = new MyClass();
}
}
4.static关键字可以修饰内部类
package com.jian.demo8;
/**
* 4.static关键字可以修饰内部类
* 4.1 什么是内部类?
* 在一个类中再编写一个类,里面的这个类称为内部类,也叫做嵌套类或者叫做内置类
* 4.2 一般什么时候定义内部类?
* 一般内部类是对外部类提供服务的,如果还想对其他外部类提供服务,则不建议编写为内部类
* 4.3 当内部类前面添加static关键字,称为静态内部类
*
*/
public class MyClass { //外部类
//编写实例方法
public void print(){
Inner i = new Inner();
}
class Inner{ //内部类,一般在外部类的实例方法中使用
}
//编写静态方法
public static void print2(){
Inner2 i2 = new Inner2();
}
static class Inner2{ //静态内部类,一般在外部类的静态方法中使用
}
}
5.static关键字可以实现静态导入
package com.jian.demo9;
/**
* 5.static关键字可以实现静态导入
*
*
*/
public class MyClass {
static int y = 100; //静态变量
}
package com.bjpowernode.demo9;
import static com.bjpowernode.demo9.MyClass.y;
public class Test {
public static void main(String[] args) {
//注意:如果在一个类中想直接使用其他类中的静态变量,则必须实现静态导入
System.out.println(y); //100
}
}