了解java面向对象编程,了解基本语法
目录- 1.包
- 2.包的访问权限控制
- 3.继承
- 4.protected 关键字
- 5.final 关键字
- 6.组合
- 7.多态
- 7.1向上转型
- 7.2动态绑定
- 7.3方法重写
- 7.4向下转型
- 7.5静态绑定
- 7.6super 关键字
- 7.7在构造方法中调用重写的方法(一个坑)
包 (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); } }
将类放到包中的基本规则
- 在文件的最上方加上一个 package 语句指定该代码在哪个包中.
- 包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.cqupt.demo1 .
- 包名要和代码路径相匹配. 例如创建 com.cqupt.demo1 的包, 那么会存在一个对应的路径 com/cqupt/demo1 来存储代码.
- 如果一个类没有 package 语句, 则该类被放到一个默认包中.
我们已经了解了类中的 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 中对于字段和方法共有四种访问权限
- private: 类内部能访问, 类外部不能访问
- 默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
- protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
- public : 类内部和类的调用者都能访问
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。
组合表示 has - a 语义
一个学校中 “包含” 若干学生和教师.。
public class Student { ... } public class Teacher { ... } public class School { public Student[] students; public Teacher[] teachers; }7.多态
使用多态的好处是什么?
- 类调用者对类的使用成本进一步降低.
封装是让类的调用者不需要知道类的实现细节.
多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法即可.
因此, 多态可以理解成是封装的更进一步, 让类调用者对类的使用成本进一步降低 - 够降低代码的 “圈复杂度”, 避免使用大量的 if - else
- 可扩展能力更强.
public static void main1(String[] args) { //向上转型 Animal animal = new Dog("jenny", 23);//父类引用 引用 子类对象 Dog dog = new Dog("james", 55); func(dog); }
此时 animal 是一个父类 (Animal) 的引用, 指向一个子类 (Dog) 的实例. 这种写法称为 向上转型.
7.2动态绑定//动态绑定 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 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定
7.3方法重写子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override)
注意:
- 重写和重载完全不一样. 不要混淆(思考一下, 重载的规则是啥?)
- 普通方法可以重写, static 修饰的静态方法不能重写
- 重写中子类的方法的访问权限不能低于父类的方法访问权限.
- 重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外)
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()方法.
7.4向下转型向上转型是子类对象转成父类对象, 向下转型就是父类对象转成子类对象. 相比于向上转型来说, 向下转型没那么常见.不是很安全
//重载 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); }7.6super 关键字
前面的代码中由于使用了重写机制, 调用到的是子类的方法. 如果需要在子类内部调用父类方法怎么办? 可以使用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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)