1 包 包是组织类的一种方式,保证类的唯一性。 如果代码中有相同的类,就会编译报错。这时可以放到不同的包中。 1.1 导入包中的类——Java提供了很多现成的类:
public class Test { public static void main(String[] args) { java.util.Date date = new java.util.Date();//java.util包中的Date类 System.out.println(date.getTime()); } }或者写成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.* 1.2 静态导入 使用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); } }1.3 包中的访问权限 当输入int a = 10;时,int前没有标明权限时,默认为default,只能访问在同一个包中的信息,无论在包中是否在同一个类里。
2 继承 为了方便代码调用。将公共代码放到一个单独的类中,让其他的类可以继承这个单独的类。这个单独的类里面包含的属性和方法,都自动被新的类支持进去。同时,新的类可以有自己独特的扩展。子类会继承父类所有的属性和方法。 2.1 基本语法 class 子类 extends 父类{ } 注意,一个子类只能继承一个父类。子类的实例中,也包含着父类的实例,可以使用super关键字得到父类实例的引用。 2.2 protected 继承中的封装,用portected关键字,无论是同一包中的子类还是不同包中的子类,都可以调用字段和方法。只有不同包的非子类才不能调用。 2.3 final 理论上可以无限制的继承下去,但一般不超过3,并且可以在最后一个子类加上final来表示该类无法再被继承。
3 多态 “一个引用,能表现出多种不同的形态”。当父类引用子类对象,并且父类和子类有同名覆盖的方法,这时,如果通过父类引用调用这个重名方法,就会发生动态绑定。封装是为了不让调用者知道类的实现细节(但还是知道是个啥类),多态更进一步,只要知道有某个方法就行。 3.1 向上转型 一个父类的引用指向一个子类的实例。例如:
class Animal{ //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); } } class Bird extends Animal{ //Bird子类 public Bird(String name) { //继承父类属性 super(name); } public void eat(String food){ //重写父类方法 System.out.println("我是一只小鸟"); System.out.println(this.name + "正在吃" + food); } public void fly(){ //子类特有方法 System.out.println(this.name + "正在飞"); } } public class test1 { //向上转型1 public static void main(String[] args) { Animal bird = new Bird("小小鸟"); //直接赋值,父类引用指向子类实例,在这里发生向上转型 bird.eat("谷子"); //父类必须有eat方法 ,发生动态绑定,重写父类eat方法 } }运行结果为: 我是一只小鸟 小小鸟正在吃谷子
public class test2 { //向上转型2 public static void main(String[] args) { Bird bird = new Bird("小小鸟"); feed(bird); //方法传参 } public static void feed(Animal animal){ animal.eat("谷子"); } }运行结果为: 我是一只小鸟 小小鸟正在吃谷子
public class test3 { //向上转型3 public static void main(String[] args) { Animal animal = findMyAnimal();//方法返回 animal.eat("小米"); } public static Animal findMyAnimal(){ Bird bird = new Bird("圆圆"); return bird; } }运行结果为: 我是一只小鸟 圆圆正在吃小米 3.2 动态绑定 子类与父类中同时出现同名的方法,具体执行时调用哪个方法,就要看这个引用指向的是父类对象还是子类对象,这个过程是程序运行时决定的(不是编译期),因此成为动态绑定。test1中有所体现。 3.3方法重写 重写也可以叫覆写/覆盖(Override)。与重载不同。重写中子类的方法访问权限不能低于父类的访问权限。针对重写,可以用@Override来显示指定。
class Shape{ //父类 public void draw(){ //父类方法 } } class Cycle extends Shape{ @Override //重写 public void draw() { System.out.println("⚪"); } } class Triangle extends Shape{ @Override public void draw() { System.out.println("▲"); } } class Flower extends Shape{ @Override public void draw() { System.out.println("❀"); } } public class test1 { public static void main(String[] args) { Shape shape1 = new Flower(); Shape shape2 = new Cycle(); Shape shape3 = new Triangle(); drawShape(shape1); drawShape(shape2); drawShape(shape3); } public static void drawShape(Shape shape){ shape.draw(); } }最终结果为打印出三种形状。 使用多态的好处 (1)类的调用者对类的使用成本降低 (2)避免大量的if-else,降低全复杂度 (3)如需新增,改动成本低 3.4 向下转型 将父类的对象转为子类的对象
public static void main(String[] args) { Animal animal = new Bird("圆圆"); animal.eat("谷子"); //animal.fly(); //错误 ((Bird) animal).fly(); //强转成Bird型,但不能转成Cat型 //因为new出的是bird实例编译过程中,animal的类型是Animal,因此,编译器只知道有一个eat方法,没有fly方法,虽然animal指向一个Bird对象,,但编译器是以animal的类型来查找方法。对于Animal animal = new Bird(“name”)这样的代码:(1)编译器检测有哪些方法的存在,只看Animal这个类型;(2)执行时到底执行父类还是子类,看的是Bird这个类型。
Animal animal1 = new Bird("扁扁"); if (animal1 instanceof Bird) { //always true Bird bird = (Bird) animal1; bird.fly(); } System.out.println("============="); Animal animal2 = new Cat("小猫"); if(animal2 instanceof Bird){ //always false Bird bird1 = (Bird) animal2; bird1.fly(); } // 不执行,new出的Cat实例,不是Bird System.out.println("-----------"); }instanceof可以判定一个引用是否是某个类的实例,是就返回true,执行if中的语句。
4 抽象类 在3.3中父类Shape中的draw方法没有实际工作,绘制方法都是由子类的draw方法实现。这样的父类可以设计成一个抽象方法,包含抽象方法的类就被成为抽象类。
abstract class Shape{ abstract public void draw(); }draw方法前加上abstract关键字,表示这是一个抽象方法,同时抽象方法没有方法体(没有{},不能有具体执行的代码)对于包含抽象方法的类,必须加上abstract关键字表示这是一个抽象类。 注意:(1)抽象类不能直接实例化。 //Shape shape = new Shape(); //编译出错(2)抽象方法不能是private(3)抽象类中可以包含其他非抽象方法。
abstract class Shape2{ //抽象类 abstract public void draw(); //抽象方法,想要使用必须构建子类并在其中重写 void func(){ //非抽象方法 System.out.println("func()"); } } class Rect extends Shape2{ @Override public void draw() { //实现(重写)抽象方法 System.out.println("draw(Rect)"); } } public class test8 { public static void main(String[] args) { Shape2 shape2 = new Rect(); //向上转型 shape2.func(); //非抽象 shape2.draw(); //抽象 } }运行结果: func() draw(Rect) 抽象类本身不能被实例化,要想使用,只能创建抽象类的子类,让子类重写抽象类中的抽象方法。
5 接口 接口是类的更进一步,抽象类中还可以包含非抽象方法,但接口中的方法都是抽象方法。字段只能包含静态常量。
interface IShape{ public abstract void draw(); //public abstract可以省略 public static final int num = 10; //public static final可以省略 } class Cycle implements IShape{ @Override public void draw() { //public不能省略 System.out.println("⚪"); } } public class test6 { public static void main(String[] args) { IShape shape = new Cycle(); shape.draw(); } }使用interface定义一个接口;方法一定是抽象的,可以省略abstract;方法一定是public的,可以省略public;Cycle用implements继承接口;调用时可以创建一个接口的引用,对应到一个子类的实例。接口不能被单独实例化。 在Java中只支持单继承,一个类只能extends一个父类,但可以同时实现多个接口,也能到达多继承类似的效果。
class Animal1{ //父类 private String name; public Animal1(String name){ this.name = name; } } interface IFlying{ //接口 void fly(); } interface IRunning{ void run(); } interface ISwimming{ void swim(); } class Cat1 extends Animal implements IRunning{ // 先继承 再接口 public Cat1(String name) { super(name); } @Override public void run() { System.out.println(this.name + "正在用四条腿跑"); } } class Fish extends Animal implements ISwimming{ public Fish(String name) { super(name); } @Override public void swim() { 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 Robot implements IRunning{ //不用继承也可以实现接口 private String name; protected Robot(String name) { this.name = name; } @Override public void run() { System.out.println(this.name + "用轮子跑"); } } public class test7 { public static void main(String[] args) { Cat1 cat = new Cat1("小猫"); walk(cat); Frog frog = new Frog("小青蛙"); walk(frog); Robot robot = new Robot("机器"); walk(robot); } public static void walk(IRunning running){ System.out.println("去散步"); running.run(); } }接口之间也可以实现继承,甚至是多继承
interface IRunning{ void run(); } interface ISwimming{ void swim(); } interface IAmphibious extends IRunning,ISwimming{ //接口继承多个接口(extends) } class Frog implements IAmphibious{ //类和接口之间是实现(implements) }学生成绩排序
import java.util.Arrays; class Student implements Comparable{ private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } @Override public String toString(){ return "[" + this.name + ":" + this.score + "]"; } @Override public int compareTo(Object o) { Student s = (Student)o; if (this.score > s.score){ return -1; }else if(this.score < s.score){ return 1; }else{ return 0; } } } public class test{ public static void main(String[] args) { Student[] students = new Student[]{ new Student("zhangsan",95), new Student("lisi",96), new Student("wangwu",97), new Student("zhaoliu",92), }; Arrays.sort(students); System.out.println(Arrays.toString(students)); } }附1 权限之间的区别 附2 重载与重写 附3 抽象类与接口