目录
包
导入包中的类
静态导入
将类放到包中
包的访问控制权限
继承
final关键字
super关键字
protected 关键字
组合
多态
向上转型
动态绑定
方法重写
理解多态
抽象类
接口
小结
什么是包?
public class Test {
public static void main(String[] args) {
int[] arr={1,2,3,4,5};
System.out.println(Arrays.toString(arr));
}
}
这个就是导入包中的类,我们在在写代码的时候,要用一些已经写好的函数,我们就需要导入它,就是导入包中的类。我们需要哪个方法或者字段就引用哪个方法或者字段。
我们可以通过下图方式看到until这个包中的Arrays这个类。
那么package和import有什么区别呢?
package:“包”,指类所在的包
import:“引入”,引入类中所需要的类
import只能导入一个具体的类,不能导入一个包。
对于上面那种导入包中的类,我们还可以用*代替这个包中所有的类,until中有很多类,Java处理的时候会拿到自己想要的,并不是所有类都拿出来。
import java.util.*;
public class Test {
public static void main(String[] args) {
int[] arr={1,2,3,4,5,6};
System.out.println(Arrays.toString(arr));
}
}
但是这种方法也有不好的地方,例如:
import java.sql.*;
public class Test {
public static void main(String[] args) {
// util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
Date date = new Date();
System.out.println(date.getTime());
}
}
// 编译出错
Error:(5, 9) java: 对Date的引用不明确
java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配
所以写完整的类名比较好。
import static java.lang.System.*;
public class Test {
public static void main(String[] args) {
out.println("hello");
}
}
静态导入的好处:
import static java.lang.Math.*;
public class Test {
public static void main(String[] args) {
double x = 30;
double y = 40;
// 静态导入的方式写起来更方便一些.
// double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
double result = sqrt(pow(x, 2) + pow(y, 2));
System.out.println(result);
}
}
上面讲的都是从包中导入一个具体的类,那我们怎么自己创建一个包,把类放到包中呢?
接下来我们可以看我们的磁盘目录结构已经被IDEA自动创建出来了:
同时我们也可以看到,在新创建的TestDemo.java文件的最上方出现了一个package语句。该package 语句指定该代码在哪个包中。
我们已经了解了类中的 public 和 private,private 中的成员只能被类的内部使用。(如果对private不懂得可以去我这篇文章看看)
package com.caicai.demo1;
public class Demo1 {
int value = 0;
}
Demo2.java:
package com.caicai.demo1;
public class Demo2 {
public static void main(String[] args) {
Demo1 demo = new Demo1();
System.out.println(demo.value);
}
}
// 执行结果, 能够访问到 value 变量
10
Test.java:
import com.caicai.demo2;
public class Test {
public static void main(String[] args) {
Demo1 demo = new Demo1();
System.out.println(demo.value);
}
}
// 编译出错
Error:(6, 32) java: value在com.caicai.demo2中不是公共的; 无法从外部程序包中对其进行访问
总结:包的访问控制权限就是说如果某个成员不含关键字public或者private,则该成员只能在该包内的其他类中使用,不能在其他包中使用。
什么是继承:
(简单来说就是几个类中有完全相同的成员或者方法,我们可以把这些相同成员或者方法放在一个类(假设放在A)中,其他类(B,C……)可以通过继承来使用。A就是父类,B,C……就是子类。
继承的意义是为了代码的复用。
此时我们举个例子来看:
// Animal.java
public class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
// Cat.java
class Cat {
public String name;
public Cat(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
// Bird.java
class Bird {
public String name;
public Bird(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
public void fly() {
System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
}
}
此时我们就可以让 Cat 和 Bird 分别继承 Animal 类, 来达到代码重用的效果。
总结:
class 子类 extends 父类 {}
对于上面的代码, 可以使用继承进行改进. 此时我们让 Cat 和 Bird 继承自 Animal 类, 那么 Cat 在定义的时候就不必再写 name 字段和 eat 方法.
class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
class Cat extends Animal {
public Cat(String name) {
// 使用 super 调用父类的构造方法.
super(name);
}
}
class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void fly() {
System.out.println(this.name + "正在飞");
}
}
public class Test {
public static void main(String[] args) {
Cat cat = new Cat("小黑");
cat.eat("猫粮");
Bird bird = new Bird("圆圆");
bird.fly();
}
}
extends 英文原意指 "扩展". 而我们所写的类的继承, 也可以理解成基于父类进行代码上的扩展。
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void fly() {
System.out.println(this.name + "正在飞");
}
}
// 编译出错
Error:(19, 32) java: name 在 Animal 中是 private 访问控制
注意:
1、使用 extends 指定父类。
2、Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承)。
不出现在静态方法中!!!(因为他是父类对象的引用,依赖对象,而被static修饰之后以后的方法和成员依赖类,不依赖对象。)
1、super();//调用父类的构造方法。//必须放第一行
2、super.func();//调用父类的方法。
3、super.data;//调用父类的成员变量。
这时候我们可以知道super跟我们之前学到的this关键字很像:
1、this()-->调用当前对象的其他构造方法。//必须放第一行
2、this.func()-->调用当前对象的方法。
3、this.date-->调用当前对象的成员变量。
他们都是用来调用,只是调用的对象不同,用法是相似的。
// Animal.java
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
// Bird.java
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void fly() {
// 对于父类的 protected 字段, 子类可以正确访问
System.out.println(this.name + "正在飞");
}
}
// Test.java 和 Animal.java 不在同一个包之中了.
public class Test {
public static void main(String[] args) {
Animal animal = new Animal("小动物");
System.out.println(animal.name); // 此时编译出错, 无法访问 name
}
}
public class Student {
...
}
public class Teacher {
...
}
public class School {
public Student[] students;
public Teacher[] teachers;
}
//1、
Bird bird = new Bird("圆圆");
//或者如下:
//2、
Animal bird = new Bird("圆圆");
public class Test {
public static void main(String[] args) {
Bird bird = new Bird("圆圆");
feed(bird);
}
public static void feed(Animal animal) {
animal.eat("谷子");
}
}
// 执行结果
圆圆正在吃谷子
方法返回:
public class Test {
public static void main(String[] args) {
Animal animal = findMyAnimal();
}
public static Animal findMyAnimal() {
Bird bird = new Bird("圆圆");
return bird;
}
}
// Animal.java
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println("我是一只小动物");
System.out.println(this.name + "正在吃" + food);
}
}
// Bird.java
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void eat(String food) {
System.out.println("我是一只小鸟");
System.out.println(this.name + "正在吃" + food);
}
}
// Test.java
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal("圆圆");
animal1.eat("谷子");
Animal animal2 = new Bird("扁扁");
animal2.eat("谷子");
}
}
// 执行结果
我是一只小动物
圆圆正在吃谷子
我是一只小鸟
扁扁正在吃谷子
此时, 我们发现:
简而言之动态绑定也称运行时绑定:通过父类引用调用父类和子类同名的覆盖方法。
编译时绑定:通过函数的重载实现的。编译的时候,会根据你给的参数的个数和类型,在编译期,确定你最终调用的一个方法。
// Bird.java
public class Bird extends Animal {
@Override
private void eat(String food) {
...
}
}
class Shape {
public void draw() {
// 啥都不用干
}
}
class Cycle extends Shape {
@Override
public void draw() {
System.out.println("○");
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("□");
}
}
class Flower extends Shape {
@Override
public void draw() {
System.out.println("♣");
}
}
/我是分割线//
// Test.java
public class Test {
public static void main(String[] args) {
Shape shape1 = new Flower();
Shape shape2 = new Cycle();
Shape shape3 = new Rect();
drawMap(shape1);
drawMap(shape2);
drawMap(shape3);
}
// 打印单个图形
public static void drawShape(Shape shape) {
shape.draw();
}
}
//打印结果:♣ ○ □
abstract class Shape {
abstract public void draw();
}
Shape shape = new Shape();
// 编译出错
Error:(30, 23) java: Shape是抽象的; 无法实例化
abstract class Shape {
abstract private void draw();
}
// 编译出错
Error:(4, 27) java: 非法的修饰符组合: abstract和private
abstract class Shape {
abstract public void draw();
void func() {
System.out.println("func");
}
}
class Rect extends Shape {
...
}
public class Test {
public static void main(String[] args) {
Shape shape = new Rect();
shape.func();
}
}
// 执行结果
func
interface IShape {
void draw();
}
class Cycle implements IShape {
@Override
public void draw() {
System.out.println("○");
}
}
public class Test {
public static void main(String[] args) {
IShape shape = new Rect();
shape.draw();
}
}
interface IShape {
void draw();
public static final int num = 10;
}
扩展 (extends) vs 实现 (implements)扩展指的是当前已经有一定的功能了 , 进一步扩充功能 。实现指的是当前啥都没有 , 需要从头构造出来 。
接下来介绍一个常用接口Comparator接口这是一个比较接口,介绍如下:
举个例子:
class Student {
public int age;
public String name;
public double score;
public Student(int age, String name, double score) {
this.age = age;
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", score=" + score +
'}';
}
}
class AgeComparator implements Comparator {
@Override
public int compare(Student o1, Student o2) {
return o1.age-o2.age;
}
}
class NameComparator implements Comparator{
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
class ScoreComparator implements Comparator{
@Override
public int compare(Student o1, Student o2) {
return (int)(o1.age-o2.age);
}
}
public class Test {
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student(12,"allay",92.0);
students[1]=new Student(8,"belly",91.0);
students[2]=new Student(16,"cidy",96.0);
AgeComparator ageComparator=new AgeComparator();
ScoreComparator scoreComparator=new ScoreComparator();
NameComparator nameComparator=new NameComparator();
System.out.println(ageComparator.compare(students[0],students[1]));
System.out.println(scoreComparator.compare(students[0],students[1]));
System.out.println(nameComparator.compare(students[0],students[1]));
}
}
它可以实现多种数据类型的比较,用起来方便。
以上就是今天的内容了,欢迎大家✌关注、✌点赞、✌留言,有什么问题都可以在评论区留言哦!