包
组织类的一种方式(就是一个文件夹)
· 在DOWS框里编译运行包里的TestDemo1
编译程序目录分割用\(如:javac com\bit\TestDemo1.java)
运行程序目录分割用.(如:java com.bit.TestDemo1.java)
· 我的TestDemo1在E:\decode\com\bit\TestDemo1里
要在decode目录下编译运行TestDemo1
package com.bit;//声明一下TestDemo1在哪个包里
public class TestDemo1 {
public static void main(String[] args) {
System.out.println("java");
}
}
要在decode\com\bit目录下编译运行,不需要导入包
·包的命名:小写字母,采用公司网站倒叙
例:www.baidu.com->包名:com.baidu.www;
· 导入一个包中的类
用谁导入谁 如果编译器区分不了 只能自己指定
动态导入
import java.util.*;//导入util下所有的包
import java.util.Arrays;//导入util下的Arrays包
静态导入(不常用)
import static java.lang.System.*;
public class TestDemo1 {
public static void main(String[] args) {
out.println("hello");//可以直接out.println,可以让代码看起来简洁一点
}
}
· 将类放入包中
查看启动jvm位置
· 访问权限
包访问权限:默认只能访问一个包里的内容
· 常见的包
- java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
- java.lang.reflect:java 反射编程包;
- java.net:进行网络编程开发包。
- java.sql:进行数据库开发的支持包。
- java.util:是java提供的工具程序包。(集合类等) 非常重要
- java.io:I/O编程开发包。
继承
为了代码复用 -----------------is-a语义
· Java是单继承
· oop(面向对象语言)特征:继承、封装、多态
· 关键字:子类/派生类 extends 父类/基类/超类
· 子类继承父类除构造方法外所有东西,所以继承后要帮助父类进行构造(用super())
· super():调用父类构造方法必须放在第一行
super.func();调用父类方法
super.data;调用父类数据成员
· 要构造子类,必须先构造父类
🐕是一个动物
🐱是一个动物
父类:Animao
package com.src.demo1;
public class Animal {
private String name;
private int age;
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 eat(){
System.out.println(this.name+"eat()");
}
}
子类:Cat
package com.src.demo1;
public class Cat extends Animal{//Cat继承Animal
//private String name; //从父类继承,可省略
//private int age;
private String sex;
public Cat(String name,int age,String sex){
super(name,age);//必须放在第一行
//this.name = name;//从父类继承不用再写
//this.age = age;
this.sex = sex;//sex为Cat特有的,无法省略
}
public void jump(){
System.out.println(this.getName()+"jump");
}
/*public void eat(){
System.out.println(this.getName()+"eat()"); //从Animal继承
}*/
}
子类:Dog
package com.src.demo1;
public class Dog extends Animal{
private String sex;
public Dog(String name,int age,String sex){
super(name,age);//必须放在第一行
this.sex = sex;
}
public void dark(){
System.out.println(this.getName()+"wangwang");
}
}
测试类
package com.src.demo1;
public class Test {
public static void main(String[] args) {
Cat cat = new Cat("mimi",2,"man");
cat.eat();
Dog dog = new Dog("wangcai",2,"man");
dog.dark();
}
}
运行结果:
· 基类只能访问自己的成员 或 方法
· final修饰的类不能被继承(密封类)
protected关键字
为了继承出现
· 各个关键字的权限
private: 类内部能访问, 类外部不能访问
默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
public : 类内部和类的调用者都能访问
组合
表达类之间的关系,达到代码复用 -----------a part of / has a语义
· 将一个类的实例作为另外一个类的字段
例:
public class Student {
...
}
public class Teacher {
...
}
public class School {
public Student[] students;
public Teacher[] teachers;
}
多态
· 向上转型
· 简单理解:父类引用子类对象
还是动物为父类🐱和🐕为子类的代码基础上
public class TestDemo1 {
public static void main(String[] args) {
Animal animal = new Animal("动物",19);
Cat cat = new Cat("mimi",2,"man");
animal = cat;//向上转型
animal.eat();//现在的anmimal指向Cat对象
}
}
运行结果:
也可以在直接写成:
public class TestDemo1 {
public static void main(String[] args) {
Animal animal = new Cat("mimi",2,"man");
animal.eat();
}
}
· 父类只可以调用父类自己的方法或者成员属性(annimal无法调用猫的jump()方法)
⭐ 假如在animal和cat类里都写入public void eat()方法,打印出来是cat中eat()方法里的内容
原因:运行时绑定(在构造方法内也可发生)------也叫做多态
javap -c查看反汇编
invokestatic调用静态方法/静态绑定
程序在编译时确实调用的是Animal的方法,但是在运行时调用了cat的方法
· 这里Animal里的eat和cat里的eat发生了重写/覆盖
· 重写和重载
重写:override 方法名相同,参数列表相同 返回值相同
范围:继承关系
限制:被覆盖的方法不能拥有比父类更严格的访问控制权限
注意事项:
- 方法不能是private
- 子类的方法权限要大于父类的方法权限
- 不能是静态的方法
重载:overlode 方法名相同,参数列表不同 返回值无要求
范围:一个类
限制:没有权限要求
· 向上转型发生时机
- 直接赋值
Animal animal = new Cat("mimi",2,"man");
- 方法传参
public class TestDemo1 {
public static void func(Animal animal){
animal.eat();
}
public static void main(String[] args) {
Cat cat = new Cat("mimi",2,"man");
func(cat);
}
}
- 方法返回
public class TestDemo1 {
public static Animal func2(){
Cat cat = new Cat("mimi",3,"man");
return cat;
}
public static void main(String[] args) {
Animal animal = func2();
}
}
· 多态
· 发生多态(运行时多态)的条件
- 有继承关系-》父类需要引用子类对象(向上转型)
- 通过父类的引用调用子类和父类同名的覆盖方法
· 底层实现
方法表在编译期间已经形成
· 向下转型
· 简单理解:将父类通过强转赋值给子类的引用
增加一个鸟的类并继承Animal,增加方法fly()
public class Bird extends Animal{
public String feather;
public Bird(String name, int age, String feather) {
super(name, age);
this.feather = feather;
}
public void fly(){
System.out.println("fly()");
}
}
public class TestDemo1 {
public static void main(String[] args) {
Animal animal= new Bird("niao ",3,"black");
animal.eat();
Bird bird = (Bird)animal;
bird.fly();//animale无法直接调用fly(),只能将其强转为Bird类型来调用fly()方法
}
}
这里的animal就发生了向下转型
· 向下转型一般不建议使用
public class TestDemo1 {
public static void main(String[] args) {
Animal animal= new Bird("niao ",3,"black");
animal.eat();
Cat cat = (Cat)animal;//发生问题处
cat.jump();
}
}
运行结果:
发生了类型转换异常
此处先将bird向上转型为animal,又将animal向下转型为cat,类型不匹配,故发生异常;上一个代码,先将bird向上转型为animal,又将animal向下转型为bird,类型匹配,故可以正常运行
· 即要发生向下转型,必须先进行同类型的向上转型
· super关键字
super 表示获取到父类实例的引用
· 使用:
1) 来调用父类的构造器
public Bird(String name) {
super(name);
}
2)来调用父类的普通方法
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
@Override
public void eat(String food) {
// 修改代码, 让子调用父类的接口.
super.eat(food);
System.out.println("我是一只小鸟");
System.out.println(this.name + "正在吃" + food);
}
}
· super关键字和this关键字的区别
this:访问本类中的属性和方法
查找范围:先查找本类,若没有就调用父类
特殊:表示当前对象的引用
super:由子类访问父类中的属性和方法
查找范围:不查找本类,而直接调用父类定义
特殊:无
· 理解多态
写一些只关注父类的代码, 就能够同时兼容各种子类的情况.
· 例子:
类的实现部分:
class Shap{
public void drow(){
}
}
class Rect extends Shap{
@Override
public void drow() {
//super.drow();
System.out.println("♦");
}
}class Cycle extends Shap{
@Override
public void drow() {
System.out.println("⚪");
}
}
class Triangle extends Shap{
@Override
public void drow() {
System.out.println("🔺");
}
}
类的调用部分:
public class TestDemo1 {
public static void drawMap(Shap shap){
shap.drow();
}
public static void main(String[] args) {
Shap shap1 = new Rect();
Shap shap2 = new Cycle();
Shap shap3 = new Triangle();
drawMap(shap1);
drawMap(shap2);
drawMap(shap3);
}
}
drawMap()方法参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当前的 shape 引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现(和 shape 对应的实例相关), 这种行为就称为多态.
· 使用多态的好处
- 类调用者对类的使用成本进一步降低.
· 封装是让类的调用者不需要知道类的实现细节.
· 多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法即可. - 能够降低代码的 “圈复杂度”, 避免使用大量的 if - else
- 可扩展能力更强.
抽象类
· 包含抽象方法的类叫抽象类
abstract class Shap2{
//abstract:抽像方法
public abstract void draw();//没有具体实现的方法
}
public class TestDemo2 {
public static void main(String[] args) {
}
}
· 抽象类不能被实例化
· 抽象类当中可以有抽象方法 也可以有非抽象方法或者成员变量
· 为了被继承而产生,继承后必须重写里面的抽象方法
· 抽象类不能是私有的
· 抽象类A继承抽象类B,A可以不重写B里的抽象方法
· 抽象类A如果重写了,类C继承的话可以不进行重写;如果A没有重写,C继承A时要进行重写
接口
· 关键字interface定义
· 接口中的方法全部不能有具体实现(即都是抽象方法)
public interface IShap {
//int size = 10 ---》成员变量默认为public static final的
void draw();//默认为public abstract的
}
· 接口当中的方法尽量简洁
· 接口中的成员变量默认为public static final的
· 接口不能单独被实例化
· 存在意义:被继承
· 类----实现---->接口
只要类(普通类)实现接口,那么接口当中的方法必须重写
· 只要类和接口存在实现关系,就可以发生向上转型
· 在调用的时候可以创建一个接口的引用, 对应到一个子类的实
class Rect3 implements IShap{
@Override
public void draw() {
System.out.println("♦");
}
}
class Cycle3 implements IShap{
@Override
public void draw() {
System.out.println("⚪");
}
}
public class TestDemo3 {
public static void drawMap(IShap shap){
shap.draw();
}
public static void main(String[] args) {
IShap iShap = new Cycle3();
IShap iShap1 = new Rect3();
drawMap(iShap);
drawMap(iShap1);
}
}
· 扩展(extends) vs 实现(implements)
扩展指的是当前已经有一定的功能了, 进一步扩充功能.
实现指的是当前啥都没有, 需要从头构造出来.
· 接口可以同时实现多个;继承只能继承一个
class Rect3 implements IShap,IShap1,IShap2,...{
....
}
例:
一个动物类
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 Cat extends Animal implements IRunning {
public Cat(String name) {
super(name);
}
@Override
public void run() {
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 + "正在蹬腿游泳");
}
}
继承表达的含义是 is - a 语义, 而接口表达的含义是 具有xxx特性
· 类和接口是实现关系,接口和接口是继承关系
⭐Compearable接口
自定义类型排序时要implements Comparable< >接口,并重写其compearTo方法
import java.util.Arrays;
//自定义类型排序时要实现implements Comparable<Student>,并重写其方法
class Student implements Comparable<Student>{//Compearable接口进行排序,<要排序的类型>
public String name;
public int age;
public double score;
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
@Override
public int compareTo(Student o) {
//return this.age - o.age;//传进来的age和当前的age进行比较
return this.name.compareTo(o.name);//-->对名字进行比较
}
}
public class Test {
public static void sort(Comparable[] comparables){//传的类型是实现Compearable接口的
//冒泡
for (int i = 0; i < comparables.length ; i++) {
for (int j = 0; j < comparables.length-i-1; j++) {
if(comparables[j].compareTo(comparables[j+1])>0){
Comparable tmp = comparables[j + 1];
comparables[j + 1] = comparables[j];
comparables[j] = tmp;
}
}
}
}
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student("lala",5,39);
students[1] = new Student("bibi",9,89);
students[2] = new Student("dodo",1,9);
System.out.println(Arrays.toString(students));
//Arrays.sort(students);//Arrays.sort排序时实现Compearable接口
sort(students);
System.out.println(Arrays.toString(students));
}
}
⭐Cloneable接口
自定义类型克隆时要implements Cloneable接口,并重写其clone方法
class Person implements Cloneable{
public String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test2 {
public static void main1(String[] args) throws CloneNotSupportedException{
Person person = new Person();
person.name = "caocao";
System.out.println(person.name);
System.out.println("clone");
Person person1 = (Person) person.clone();
person1.name = "liubei";
System.out.println(person.name);
System.out.println(person1.name);
}
}
加油鸭!🦆🦆🦆