包是组织类的方式,使用包的主要目的是保证类的唯一性。
路径不同,则就是唯一的,例如:同事与你写了一个同样名字的类,就会导致冲突,导致编译无法通过
包其实是一个文件夹
1.使用导入包的方式来使用系统包
在java文件夹中有这样一个文件(一般为压缩文件,这是解压后文件),储存着java的源代码中的包
像这种头文件叫做导入包
使用*的时候,导入所有的包(你使用那个包时自动导入)
2.不使用系统包的方式来导入包
例:
使用这种方式来进行导入,标明好路径。
import java.util.*; import java.sql.*;
在这两个包中同时拥有Date这个类,会导致歧义,以至于编译器无法识别,在这种情况下,就不能使用导入系统包的方式来进行,而必须写完整的类名
import static java.lang.System.*;
这种导入是静态导入导入这种包后,常使用的打印函数就可以这样写
out.println("haha");
import java.lang.*;//系统常用的基础类(String、Object),此包从JDK1.1后自动导入。 import java.lang.reflect.*;//反射编程包; import java.net.*;//进行网络编程的开发包 import java.sql.*;//进行数据库编程的开发包 import java.util.*;//是java提供的工具程序包。(集合类等) import java.io.*;//I/O编程开发包。
在编写类时,可能会有很多相同的属性及方法。
例:
class dog{ public String name; public int age; public void eat(){ System.out.println("chi()"); } public void crow(){ System.out.println("wangwang"); } } class cat{ public String name; public int age; public void eat(){ System.out.println("chi()"); } public void fly(){ System.out.println("fly()"); } }
这时候就可以使用继承,把相同的属性或方法包装起来,其他类来继承
class animal{ public String name; public int age; public void eat(){ System.out.println("chi()"); } } class dog extends animal{ public void crow(){ System.out.println("wangwang"); } } class bird extends animal{ public void fly(){ System.out.println("fly()"); } }
在上述例子中:
dog类extends了animal
这时
dog:子类 、 派生类
animal:父类、基类、超类
可以进行代码的复用。
若父类方法中有参数或方法是被private修饰,则使用时不能进行使用。
class animal{ private String name; public int age; public void eat(){ System.out.println("chi()"); } } public static void main(String[] args) { Dog dog = new Dog(); System.out.println(dog.name+"hh"); }
此时调用时则会进行报错。
答:除构造方法之外的所有都被继承了。
子类的构造需要先帮助父类对象进行构造(调用父类的构造方法)。
class Animal{ private String name; public int age; public void eat(){ System.out.println("chi()"); } public Animal(String name){ this.name=name; } } class Dog extends Animal{ public String sex; public Dog(String name,String sex){ super(name); //注:用super来给父类构造时要放到第一行,否则会报错。 this.sex=sex; } public void crow(String name){ System.out.println("wangwang"); } }
否则程序会进行报错。
super的三种使用方式:
class A{ } class B extends A{ } class C extends B{ } class D extends C{ }
注:这种继承关系最多不要超过三层,若不想被继承需要使用final来修饰来防止不被继承。
class A{ public int a = 1; } class B extends A{ public int a = 2; public int b = 3; } public class testw { public static void main(String[] args) { B b = new B(); System.out.println(b.a); } }
这种时候的调用a时,会调用子类的a,而不会调用父类的a。
public :公共权限
所有的文件都可以进行访问
private,:私有权限
只有在当前类中可以进行访问
protected:受保护权限
在继承时使用,在父类中有protected的属性或方法在不同包中子类继承父类时可以进行调用,使用super关键字进行调用
default:默认包访问权限
只能在当前包中进行访问
像下面这种关系就叫组合
class Student{ //类 } class teacher{ //类 } class school{ public Student[] student; public teacher[] teacher; }
字面意思:一种事物多种形态
子类对象给父类
Animal animal = new Dog("张三");
注意问题:
在Dog子类对象中创建 变量a;
在Animal父类中创建 变量b;
Animal animal = new Dog("张三"); System.out.println(animal.b); System.out.println(animal.a); //报错,父类对象无法调用子类对象 Dog dog = new Dog("李四"); System.out.println(dog.b); System.out.println(dog.a);
此时animal的类型是Animal,所以只能访问Animal类自己的成员。
向上转型的三个时机:
Animal animal = new Dog("张三");
public static void main(String[] args) { func(animal); //这三种发生向上转型 func(dog); func(new Dog("王五")); } public static void func(Animal animal){ }
public static void main(String[] args) { Animal animal1 = func1(); } public static Animal func1(){ Dog dog = new Dog("张三"); return dog; }
父类对象给子类
public static void main(String[] args) { Animal animal = new Dog("张三"); Dog dog = (Dog) animal; dog.crow(); }
注意事项:
public static void main(String[] args) { Animal animal = new Animal("张三"); Dog dog = (Dog) animal; dog.crow(); }
此时代码会进行报错,回报一个类型转换错误
所以说向下转型,必须要进行向上转型。
避免错修改:
//判断一下animal 是不是 Dog 的实例。 if(animal instanceof Dog){ Dog dog = (Dog) animal; dog.crow(); }
如果animal引用了Dog则返回true,否则false。
这样就安全了。
class Animal{ public void eat(){ System.out.println("chi()"); } } class Dog extends Animal{ @Override //注解:标识在这里发生了重写 public void eat() { System.out.println("he()"); } } public static void main(){ Animal animal = new Dog("花花"); animal.eat(); }
重载(overload)
1.方法名相同
2.参数列表不同(个数和类型)
3.返回值不做要求
重写(override)
1.方法名相同
2.参数列表相同(个数和类型)
3.返回值相同(若返回值构成协变类型)
协变类型:子类的返回值与父类之间返回值是继承关系
class Animal{ public Animal eat(){ System.out.println("chi()"); return new Animal("小花"); } } class Dog extends Animal{ @Override public Dog eat() { System.out.println("he()"); return new Dog("huahua"); } }
此时就构成了协变类型
动态绑定:
1.一定要发生向上转型
2.父类和子类有同名的重写(覆写/覆盖)方法
3.最后通过父类的引用来调用子类和父类的这个同名的覆盖方法。
此时会发生动态绑定,或者叫做运行时绑定。
注意: 在构造函数中也可以发生动态绑定(一个坑)
class Animal{ public void eat(){ System.out.println("chi()"); } public Animal(String name){ eat(); //发生动态绑定 this.name=name; } } class Dog extends Animal{ public Dog(String name){ super(name); } public void eat() { System.out.println("he()"); } } public static void main(String[] args) { Animal animal = new Dog("花花"); }
此时在父类构造方法中发生动态绑定
重写的注意事项
1.如果当前方法是静态方法,是不可以被重写的
2.子类如果要重写父类方法,那么子类的访问修饰权限要大于等于父类的权限
3.父类中要被重写的方法一定不能是,private(私有)。
4.被final修饰的方法不能被重写(密封方法)。
class Shape{ public void draw(){ } } class Cycle extends Shape{ public void draw(){ //来重写父类方法 System.out.println("矩形"); } } class Rect extends Shape{ public void draw(){ //重写父类方法 System.out.println("圆形"); } } public class testDome { public static void drawMap(Shape shape){ shape.draw(); //调用父类方法,子类方法进行重写发生动态绑定打印子类方法 } public static void main(String[] args) { Cycle cycle = new Cycle(); //new子类对象 Rect rect = new Rect(); //new子类对象 drawMap(cycle); //传参时发生向上转型 drawMap(rect); //传参时发生向上转型 } }
包含抽象方法的类就是抽象类
抽象方法是什么:被关键字abstract修饰的方法,这个方法可以没有具体的实现。
abstract class Shape{ //密封类 public abstract void draw(); //密封方法 }
抽象类的注意事项
使用关键字interface来修饰的。
interface IShape{ //接口 int a = 10; //参数默认为 public static final void draw(); //方法默认为 public abstract default void func1(){ //jdk1.8开始接口中方法有具体的实现,这个方法一定要被default修饰。 System.out.println("123"); } } class Cycle implements IShape{ @Override public void draw(){ System.out.println("○"); } } public class testDome { public static void func(IShape iShape){ iShape.draw(); } public static void main(String[] args) { //IShape iShape = new IShape(); //不能进行实例化 IShape iShape = new Cycle(); //发生向上转型 func(iShape); } }
interface A{ } interface B{ } interface C extends A,B{ }
在使用自定义类型时要使用Comparable接口
class Student implements Comparable<Student>{ public String name; public int age; public Student(String name,int age){ this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public int compareTo(Student o) { //对自定义的数据进行排序 //比较的规则 /*if (this.age > o.age){ return 1; //正值 }else if (this.age > o.age){ return -1; }else{ return 0; }*/ //return this.age - o.age; //简化方法 return this.name.compareTo(o.name); //在String中实习了compareTo方法 } } public class testDome { public static void main(String[] args) { Student[] student = new Student[3]; student[0] = new Student("caocao",18); student[1] = new Student("liubei",26); student[2] = new Student("sunquan",22); Arrays.sort(student); //数组排序 System.out.println(Arrays.toString(student)); //数组打印 } }
//类同上面Student不实现接口。 //同包不同类 public class AgeComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.age-o2.age; } } //同包不同类 public class NameComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.name.compareTo(o2.name); } } //主程序 public static void main(String[] args) { Student[] student = new Student[3]; student[0] = new Student("caocao",18); student[1] = new Student("liubei",26); student[2] = new Student("sunquan",22); NameComparator nameComparator = new NameComparator(); Arrays.sort(student,nameComparator); System.out.println(Arrays.toString(student)); }
使用比较器更方便,你想使用什么比较就自己实现一个比较器。
相比于Comparable来说,一旦类写死了一种比较方式那么就不能轻易修改了
Cloneable接口是一个空接口(标识接口),只是代表这个类是可以被克隆的。
class Student1 implements Cloneable{ //这个接口代表着这个类可以被克隆 public String name; public int age; public Student1(String name,int age){ this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } //Override Methods 中的clone @Override protected Object clone() throws CloneNotSupportedException { //接口中没有clone方法,所以需要重写Object的方法 Student1 student1 = (Student1) super.clone(); //调用父类的克隆方法给了Student1 return student1; } } public class testDome1 { public static void main(String[] args) throws CloneNotSupportedException { Student1 student1 = new Student1("caocao",18); Student1 student2 = (Student1)student1.clone(); System.out.println(student1); System.out.println(student2); } }
Cloneable中深浅拷贝问题:
浅拷贝
class Part implements Cloneable{ public int m = 10; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Student1 implements Cloneable{ //这个接口代表着这个类可以被克隆 public String name; public int age; public Part a; public Student1(String name,int age){ this.name = name; this.age = age; this.a = new Part(); } @Override public String toString() { return "Student1{" + "name='" + name + '\'' + ", age=" + age + ", a=" + a + '}'; } //Override Methods 中的clone @Override protected Object clone() throws CloneNotSupportedException { //接口中没有clone方法,所以需要重写Object的方法 Student1 student1 = (Student1) super.clone(); //调用父类的克隆方法给了Student1 student1.a = (Part)this.a.clone(); return student1; } } public class testDome1 { public static void main(String[] args) throws CloneNotSupportedException { Student1 student1 = new Student1("caocao",18); Student1 student2 = (Student1)student1.clone(); System.out.println(student1); System.out.println(student2); } }
以上方法是更改浅拷贝为深拷贝