了解java面向对象编程,了解基本语法
包 (package) 是组织类的一种方式.使用包的主要目的是保证类的唯一性.
import
导入包中的类
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
如果需要使用 java.util 中的其他类, 可以使用 import java.util.*
import java.util.*;
public class Test {
public static void main(String[] args) {
Date date = new Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
但是我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况.
比如 java.sql 中的类 java.sql.Date
和 java.util 中的类 java.util.Date
import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
// util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
Date date = new Date();
System.out.println(date.getTime());
}
}
这样就会编译失败,Date不明确。应该:
import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
java.util.Date date = new java.util.Date();
System.out.println(date.getTime());
}
}
使用 import static 可以导入包中的静态的方法和字段.
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);
}
}
将类放到包中的基本规则
com.cqupt.demo1
.com.cqupt.demo1
的包, 那么会存在一个对应的路径 com/cqupt/demo1
来存储代码.我们已经了解了类中的 public 和 private. private 中的成员只能被类的内部使用.
如果某个成员不包含 public 和 private 关键字, 此时这个成员可以在包内部的其他类使用, 但是不能在包外部的类使用.(包访问权限)
class 子类 extends 父类 {
}
class Animal {
public String name;
public int age;
private int count;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("eat()");
}
}
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
}
class Bird extends Animal {
public Bird(String name, int age,String swing) {
super(name, age);
this.swing=swing;
}
public String swing;
public void fly() {
System.out.println(name + "fly()"+swing);
}
}
public class TestDemo {
public static void main(String[] args) {
Animal animal=new Dog("jenny",23);//父类引用 引用 子类对象
}
public static void main1(String[] args) {
Dog dog = new Dog("jenny",22);
System.out.println(dog.name);
dog.eat();
Bird bird = new Bird("james",45,"我要的飞翔");
System.out.println(bird.name);
bird.eat();
bird.fly();
}
}
1. 使用 extends 指定父类.
2. Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
3. 子类会继承父类的所有 public 的字段和方法.
4. 对于父类的 private 的字段和方法, 子类中是无法访问的.
5. 子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用
刚才我们发现, 如果把字段设为 private, 子类不能访问. 但是设成 public, 又违背了我们 “封装” 的初衷.
两全其美的办法就是 protected 关键字:
对于类的调用者来说, protected 修饰的字段和方法是不能访问的
对于类的 子类 和 同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的
总结::Java 中对于字段和方法共有四种访问权限
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。
组合表示 has - a 语义
一个学校中 “包含” 若干学生和教师.。
public class Student {
...
}
public class Teacher {
...
}
public class School {
public Student[] students;
public Teacher[] teachers;
}
使用多态的好处是什么?
class Shape {
public void draw() {
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("◇");
}
}
class Flower extends Shape {
@Override
public void draw() {
System.out.println("❀");
}
}
class Triangle extends Shape {
@Override
public void draw() {
System.out.println("△");
}
}
class Circle extends Shape {
@Override
public void draw() {
System.out.println("●");
}
}
public class Test {
public static void main(String[] args) {
Rect rect = new Rect();
Flower flower = new Flower();
Triangle triangle = new Triangle();
Circle circle=new Circle();
Shape[] shapes = {rect, flower, triangle, circle};
for (Shape shape:shapes) {
shape.draw();
}
}
public static void drawMap(Shape shape) {
shape.draw();
}
//多态:不同对象调用同一个方法产生不同的结果效果
public static void main1(String[] args) {
Rect rect = new Rect();
drawMap(rect);
Flower flower = new Flower();
drawMap(flower);
Triangle triangle = new Triangle();
drawMap(triangle);
}
}
public static void main1(String[] args) {
//向上转型
Animal animal = new Dog("jenny", 23);//父类引用 引用 子类对象
Dog dog = new Dog("james", 55);
func(dog);
}
此时 animal
是一个父类 (Animal)
的引用, 指向一个子类 (Dog)
的实例. 这种写法称为 向上转型
.
//动态绑定
public static void main2(String[] args) {
Animal animal = new Dog("jenny", 23);//父类引用 引用 子类对象
animal.eat();
Animal animal2 = new Bird("jjj", 45, "ijh");
animal2.eat();
//通过父类的引用 只能访问父类自己的成员
System.out.println(animal2.name);
}
在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定
子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override)
注意:
class Animal {
public String name;
public int age;
private int count;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(name + "eat()");
}
}
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(name + " 狼吞虎咽的 eat()");
}
//重载
public void func(int a) {
System.out.println(a);
}
public void func(int a, int b) {
System.out.println(a + b);
}
public void func(int a, int b, double n) {
System.out.println(a + b + n);
}
}
class Bird extends Animal {
public Bird(String name, int age, String swing) {
super(name, age);
this.swing = swing;
}
public String swing;
public void fly() {
System.out.println(name + "fly()" + swing);
}
}
Dog类中重写父类Animal中的eat()方法.
向上转型是子类对象转成父类对象, 向下转型就是父类对象转成子类对象. 相比于向上转型来说, 向下转型没那么常见.不是很安全
//重载
public void func(int a) {
System.out.println(a);
}
public void func(int a, int b) {
System.out.println(a + b);
}
public void func(int a, int b, double n) {
System.out.println(a + b + n);
}
//静态绑定
public static void main3(String[] args) {
Dog dog = new Dog("jenny", 34);
dog.func(3);
dog.func(2, 4);
dog.func(4, 5, 3.88);
}
前面的代码中由于使用了重写机制, 调用到的是子类的方法. 如果需要在子类内部调用父类方法怎么办? 可以使用super
关键字.
我们创建两个类, B 是父类, D 是子类. D 中重写 func 方法. 并且在 B 的构造方法中调用 func
:
class B {
public B() {
// do nothing
func();
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
//运行结果:D.func()0
1. 构造 D 对象的同时, 会调用 B 的构造方法.
2. B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
3. 此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0
abstract class Shape {
public abstract void draw();//抽象方法
}
//如果抽象类B继承抽象类A,那么抽象类B可以不实现抽象父类A中的抽象方法
abstract class A extends Shape{
public abstract void funcA();
}
//当B类被普通类继承,那么A和B这两个抽象类中的抽象方法必须在普通类重写
class B extends A{
@Override
public void draw() {
}
@Override
public void funcA() {
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("◇");
}
}
class Flower extends Shape {
@Override
public void draw() {
System.out.println("❀");
}
}
class Triangle extends Shape {
@Override
public void draw() {
System.out.println("△");
}
}
class Circle extends Shape {
@Override
public void draw() {
System.out.println("●");
}
}
public class Test {
//动态绑定
public static void drawMap(Shape shape){
shape.draw();
}
public static void main(String[] args) {
//Shape shape=new Shape();//error,抽象类不能被实例化
Shape shape=new Rect();//抽象类可以发生向上转型,子类对象赋值给父类引用
drawMap(shape);//动态绑定
}
}
抽象类的作用
接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量。
interface IShape {
public abstract void draw();//抽象方法
/* default public void func() {
System.out.println("ffff");
}
default public void func2() {
System.out.println("4332");
}
public static void funcStatic() {
System.out.println("sat");
}*/
}
//当类实现接口,就要重写接口中的抽象方法
class Rect implements IShape {
@Override
public void draw() {
System.out.println("◇");
}
}
class Flower implements IShape {
@Override
public void draw() {
System.out.println("❀");
}
}
class Triangle implements IShape {
@Override
public void draw() {
System.out.println("△");
}
}
class Circle implements IShape {
@Override
public void draw() {
System.out.println("●");
}
}
public class Test {
public static void drawMap(IShape iShape) {
iShape.draw();
}
//动态绑定
public static void main(String[] args) {
Rect rect = new Rect();
Flower flower = new Flower();
drawMap(rect);
drawMap(flower);
}
public static void main1(String[] args) {
//IIShape IIShape=new IIShape();//error,不能被实例化
IShape IShape = new Rect();
IShape.draw();
}
}
接口中只能包含抽象方法. 对于字段来说,接口中只能包含静态常量(final static).
interface IA {
public static final int A = 10;//成员变量默认是常量
int B = 10;//public static final
void funcA();//public abstract
}
class A implements IA{
@Override
public void funcA() {//子类重写父类的方法,必须加public,
// 子类的访问权限范围大于等于父类,父类默认是public
System.out.println("A::funcA");
}
}
interface IA {
public static final int A = 10;//成员变量默认是常量
int B = 10;//public static final
void funcA();//public abstract
}
interface IB {
void funcB();
}
abstract class BClass {
}
class AClass extends BClass implements IA, IB {
@Override
public void funcA() {
System.out.println("A::funcA()");
System.out.println(A);
}
@Override
public void funcB() {
System.out.println("A::funcB()");
}
}
一个类可以通过extends继承抽象类或者普通类,但是只能继承一个;同时可通过implements实现多个接口,接口之间通过’,'隔开
接口接口之间通过implements来拓展;当一个类实现一个接口C,但是接口C又拓展接口D,那么 这个类要重写接口C和D中所有的方法
interface IA1 {
void funcA();
}
interface IB1 extends IA1 {
void funcB();
}
class C implements IB1 {
@Override
public void funcA() {
System.out.println("IA1::funcA");
}
@Override
public void funcB() {
System.out.println("IB1::funcB");
}
}
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
}
//不是所有的动物都可以飞
interface IFlying {
void fly();
}
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
class Bird extends Animal implements IFlying {
public Bird(String name) {
super(name);
}
@Override
public void fly() {
System.out.println(this.name + "正在飞!");
}
}
class Frog extends Animal implements IRunning, ISwimming {
public Frog(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name + "正在跑");
}
@Override
public void swim() {
System.out.println(this.name + "正在游泳");
}
}
class Duck extends Animal implements IRunning, IFlying, ISwimming {
public Duck(String name) {
super(name);
}
@Override
public void fly() {
System.out.println(this.name + "正在飞!");
}
@Override
public void run() {
System.out.println(this.name + "正在跑");
}
@Override
public void swim() {
System.out.println(this.name + "正在游泳");
}
}
class Roobot implements IRunning{
@Override
public void run() {
System.out.println("机器人在跑!");
}
}
public class Test4 {
public static void runFunc(IRunning iRunning) {
iRunning.run();
}
public static void swimFunc(ISwimming iSwimming) {
iSwimming.swim();
}
public static void flyFunc(IFlying iFlying) {
iFlying.fly();
}
public static void main(String[] args) {
runFunc(new Duck("鸭子"));
runFunc(new Frog("青蛙"));
new Roobot().run();
}
public static void main3(String[] args) {
flyFunc(new Duck("鸭子"));
flyFunc(new Bird("小鸟"));
}
public static void main2(String[] args) {
swimFunc(new Duck("鸭子"));
swimFunc(new Frog("青蛙"));
}
public static void main1(String[] args) {
runFunc(new Duck("鸭子"));
runFunc(new Frog("青蛙"));
}
}
这个接口有很大的缺点,对类的侵入性非常强,不敢轻易改动。
如果自定义数据类型进行大小比较,一定要实现可比较的接口
class Student implements Comparable<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 +
'}';
}
@Override
//谁调用这个方法,这就是this
public int compareTo(Student o) {
/*if (this.age > o.age) {
return 1;
} else if (this.age == o.age) {
return 0;
} else {
return -1;
}*/
//return this.age-o.age;//从小到大
return o.age-this.age;//从大到小
}
}
public class Test {
public static void main2(String[] args) {
Student students1 = new Student(12, "kkk", 99.8);
Student students2 = new Student(32, "lll", 67.8);
/*if(students1.compareTo(students2)>0){
}*/
System.out.println(students1.compareTo(students2));
}
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student(12, "kkk", 99.8);
students[1] = new Student(32, "lll", 67.8);
students[2] = new Student(22, "zzz", 90.5);
System.out.println(Arrays.toString(students));
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
public static void main1(String[] args) {
int[] array = {1, 21, 3, 14, 5, 16};
System.out.println(Arrays.toString(array));
Arrays.sort(array);//从小到大排序
System.out.println(Arrays.toString(array));
}
}
对类的侵入性非常弱。
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<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
}
class ScoreComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return (int) (o1.score - o2.score);
}
}
class NameComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
public class Test {
//根据名字比较
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student(24, "kkk", 99.8);
students[1] = new Student(12, "all", 87.8);
students[2] = new Student(22, "zzz", 79.5);
System.out.println(Arrays.toString(students));
NameComparator nameComparator=new NameComparator();
Arrays.sort(students, nameComparator);
System.out.println(Arrays.toString(students));
}
//根据成绩
public static void main4(String[] args) {
Student[] students = new Student[3];
students[0] = new Student(24, "kkk", 99.8);
students[1] = new Student(12, "lll", 87.8);
students[2] = new Student(22, "zzz", 79.5);
System.out.println(Arrays.toString(students));
ScoreComparator scoreComparator = new ScoreComparator();
Arrays.sort(students, scoreComparator);
System.out.println(Arrays.toString(students));
}
public static void main3(String[] args) {
Student students1 = new Student(12, "kkk", 99.8);
Student students2 = new Student(2, "lll", 67.8);
/*if(students1.compareTo(students2)>0){
}*/
//System.out.println(students1.compareTo(students2));
AgeComparator ageComparator = new AgeComparator();
System.out.println(ageComparator.compare(students1, students2));
}
//根据年龄
public static void main2(String[] args) {
Student[] students = new Student[3];
students[0] = new Student(24, "kkk", 99.8);
students[1] = new Student(12, "lll", 87.8);
students[2] = new Student(22, "zzz", 79.5);
System.out.println(Arrays.toString(students));
AgeComparator ageComparator = new AgeComparator();
Arrays.sort(students, ageComparator);
System.out.println(Arrays.toString(students));
}
}
创建对象的方式:
对象实现cloneable
接口,里面必须重写clone()
方法:
将Person
进行克隆为person2
:
Person person = new Person();
person.age = 99;
Person person2 = (Person) person.clone();
class Person implements Cloneable {
public int age;
public void eat() {
System.out.println("吃!");
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class TestDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
person.age = 99;
Person person2 = (Person) person.clone();
System.out.println(person2);
System.out.println("================");
person2.age = 199;
System.out.println(person);
System.out.println(person2);
}
}