面向对象在百度百科中是这样解释的:“面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物”。说的好像很流弊的样子,看看就行。
1.1:包的概念
包是组织、整合类的一种方式
其目的在于保证使用类的唯一性(同一个包中,里面所包含的类名是唯一的)
比如在包A中定义了一个Test类,在包B中也定义了一个Test类,那么当使用A中的Test类时便导入包A调用A中的Test类(A.Test),以此保证类的唯一性。
1.2:导入包中的类
Java中有很多现成的包供我们使用,使用这些包的方式有两种
public class TestDemo {
public static void main(String[] args) {
java.util.Date time = new java.util.Date();
//使用 util 包中的Date类创建一个对象
System.out.println(time.getTime());
//调用该对象的 getTime 方法,获得一个毫秒级别的时间戳
}
}
上述代码中,util 就是一个包,Date就是该包中的一个类,使用时用 java.包名.类名 使用
import java.util.Date;
public class TestDemo {
public static void main(String[] args) {
Date time = new Date();
System.out.println(time.getTime());
}
第一个代码每次使用类时都要加包的前缀,太过麻烦,因此还可使用第二种方式,在代码最开头使用 import 关键字导入需要的包,这样就可以像使用自己定义的类一样,直接用类名创建对象
当同时需要同一个包中的多个类是,可以用 import.java.包名.* 的方式导入包,这样就可以使用该包下的所有类(但建议不要这么使用,否则当导入多个包时还是会出现类名重复的现象)。
1.3:静态导入
包中除了类的普通方法外,还有一些静态方法,使用这些方法时,可以使用 import static 的方式导入包中的静态字段和方法,无需创建对象直接使用
import static java.lang.Math.*;
public class TestDemo {
public static void main(String[] args) {
double x = 10.5;
double y = 3.0;
double result = sqrt(pow(x,y)+pow(x,y));
System.out.println(result);
}
1.4:自定义类放入包中
基本规则
1.5:包的访问权限控制
如果某个成员不包含 public 和 private 关键字,此时这个成员可以被包中的其他类使用,但不能在包外部类中使用
1.6:常见的系统包
1、java.lang:系统常用基础类(String,Object),jdk1.1以后自动导入
2、java.lang.reflect: java 反射编程包
3、java.net:进行网络编程开发包
4、java.sql:进行数据库开发的支持包。
5、java.util:是java提供的工具程序包。(集合类等)
6、java.io:I/O编程开发包。
2.1 概念:
当创建多个类时发现这些类之间存在一定的关联关系,则可以创建一个父类拥有这些类的相同属性和方法,让这些类继承与父类,来提高效率,达到代码重用的效果。
此时被继承的类我们成为 父类、基类或者超类,而继承的类我们称为子类或者派生类,子类会继承父类除构造方法外的其他所有东西。
2.2 语法规则:
class 子类 extend 父类{
}
class Animal{
public String name;//父类的name必须为 public 否则子类将无法访问
public Animal(String name) {
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"吃"+food);
}
}
class Dog extends Animal{
public Dog(String name){
super(name);
}
}
class Bird extends Animal{
public Bird(String name){
super(name);
}
public void fly(){
System.out.println(this.name+"正在飞");
}
}
public class TestDemo {
public static void main(String[] args) {
Dog dog = new Dog("旺旺");
dog.eat("骨头");
Bird bird = new Bird("啾啾");
bird.eat("米粒");
bird.fly();
}
2.3、protected关键字
上述代码中,如果将父类的 name 设为 private子类将无法访问,但设为 public 又违背了封装的规则,此时就需要用到 protect 关键字
小结:Java中对字段和方法共有四种访问权限
2.4、final关键字
final 可以修饰一个变量或者字段,用来表示常量
final 也恶意修饰一个类,用来表现该类不能被继承
组合:
即一个类中对另一个类的嵌套,在一个类中实例另一个类,达到代码重用的效果
3.1、向上转型:
如上代码,创建一个 Bird 的对象可以写成
Bird bird = new Bird();
也可以写成
Bird bird = new Bird();
Animal bird2 = bird;
Animal bird3 = new Bird();
此时bird2、bird3是一个父类(Animal)的引用,指向子类(bird)的实例,这称为向上转型。
向上转型发生的时机:
方法传参:
public static void main(String[] args) {
Bird bird = new Bird("啾啾");
feed(bird);
}
public static void feed(Animal animal){
animal.eat("谷子");
}
此时形参的类型是 Animal(父类) ,实际上是对应到 Bird(子类)的实例
方法返回:
public static void main(String[] args) {
findAnimal().eat("谷子");
}
public static Animal findAnimal(){
Bird bird = new Bird("啾啾");
return bird;
}
方法 findAnimal 返回值是 Animal 的一个引用,但实际指向 Bird 的一个实例
3.2:动态绑定
子类和父类出现同名方法时发生
class Animal{
public 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{
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 TestDemo {
public static void main(String[] args) {
Animal animal1 = new Animal("动物");
Animal animal2 = new Bird("小鸟");
animal1.eat("谷子");
animal2.eat("谷子");
}
执行以上代码我们发现:
在Java中,调用某个方法,究竟执行哪段代码(是父类方法还是子类),取决于看这个引用指向的对象是父类对象还是子类对象,这个过程是在运行时才决定的,因此成为动态绑定
父类引用,引用子类对象时,只能访问自己特有的,不能访问子类独有的
3.3、重写
对于上述代码,父类和子类的eat方法来说,就构成了重写
重写的注意事项:
1.要求不同
重载:a.方法名相同 b.参数列表不同 c.返回值不做要求
重写:a.方法名相同 b.参数列表相同(参数类型和个数) c.返回值也要相同
2.范围不同
重载:同一个类中
重写:继承关系,不同类中
3.限制
重载:无限制
重写:子类中重写的方法访问权限不能低于父类的访问权限
3.4、理解多态
class Shape {
public void draw(){
}
}
class Circle extends Shape{
public void draw(){
System.out.println("画一个圆圈○");
}
}
class Rectangle extends Shape{
public void draw(){
System.out.println("画一个矩形□");
}
}
class Triangle extends Shape{
public void draw(){
System.out.println("画一个三角△");
}
}
//================================================
//================================================
public class TestDemo {
public static void main(String[] args) {
Shape shape1 = new Circle();
Shape shape2 = new Rectangle();
Shape shape3 = new Triangle();
drawMap(shape1);
drawMap(shape2);
drawMap(shape3);
}
public static void drawMap(Shape shape){
shape.draw();
}
以上代码,分割线以上是由类的实现者编写的,分割线以下是由类的调用者编写的
当调用者编写drawMap方法的时候(参数类型为父类Shape),并不关心当前shape引用指向哪个类型的实例,此时shape调用的draw方法只取决于shape指向的哪个类型的实例,以实现不同的表现形式,这种思想叫做多态。
3.5、向下转型
父类引用,引用子类对象称为向上转型;子类引用,引用父类对象称为向下转型。
class Animal{
public String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food){
System.out.println("我是一只小动物");
System.out.println(this.name+"正在吃"+food);
}
}
ass Bird extends Animal{
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 TestDemo {
public static void main(String[] args) {
Animal animal = new Bird("啾啾");
animal.eat("谷子");
animal.fly();//执行该行代码时,会报错误
}
编译过程中 animal 的类型时 Animal ,编译器编译时根据类型只知道 animal 中只有一个eat方法,找不到fly方法
Animal animal = new Cat("小猫");
if (animal instanceof Bird) {
Bird bird = (Bird)animal;
bird.fly();
}
3.6、super关键字
当在子类内部要调用父类方法时,就要用到 super 关键字
super 表示获取到父类实例的引用,其有两种常用方法
一、使用 super 来调用父类的构造方法,super(参数)
public Bird(String name){
super(name);
}
二、使用 super 来调用父类的普通方法,super.方法名(参数)
class Bird extends Animal{
public Bird(String name){
super(name);
}
public void eat(String food){
super.eat(food);
System.out.println("我是一只小鸟");
System.out.println(this.name+"正在吃"+food);
}
}
上述代码中个,如果直接调用eat方法,则被编译器认为是调用子类的方法(同递归),想要调用父类方法则需要使用 super 关键字
1、概念
this:访问本类的属性和方法
super:访问父类的属性和方法
2、查找范围
this:先查找本类,子类没有再调用父类
super:不查找本类,直接调用父类
3、特殊
this:表示当前对象的引用
super:表现父类对象的引用
多态存在的意义就在于,让调用者不必关注对象的具体类型,降低用户的使用成本
4.1语法规则
类似于之前代码的父类 Shape 中的draw方法,其中并没有实际工作,而由其子类重新该方法实现,那么像这种没有实际工作的方法我们就可以用 abstract 关键字修饰把它设计成一个抽象方法,而包含抽象方法的类我们就称为抽象类
abstract class Shape {
abstract public void draw();
}
注意事项:
4.2抽象类的作用
抽象类的意义在于为了被继承
抽象类本身不能实例化,想要使用,必须创建该抽象类的子类,在子类中重写抽象方法
使用抽象类相当于多了一重编译器的检验(对于抽象了来说,如果继承的子类不重写父类的抽象方法,则会报错)
接口是比抽象类还抽象,接口只包含抽象方法,其字段也只能包含静态常量
interface IShape{
abstract public void draw();
}
class Circle implements Shape{
@Override
public void draw() {
System.out.println();
}
}
在Java中一个类只能继承一个父类,但同时可以实现多个接口
class Animal{
public String name;
public Animal(String name){
this.name = name;
}
}
interface IFlying{
void fly();
}
interface IRunning{
void run();
}
interface ISwimming{
void swim();
}
class Dog extends Animal implements IRunning{
public Dog(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+"正在游泳");
}
}
class Duck extends Animal implements IRunning,ISwimming,IFlying{
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+"正在游泳");
}
}
public class TestDemo {
public static void main(String[] args) {
Dog dog = new Dog("汪汪");
Frog frog = new Frog("呱呱");
Duck duck = new Duck("嘎嘎");
dog.run();
frog.run();
frog.swim();
duck.fly();
duck.run();
}
}
接口使用实例——给对象数组排序
创建一个学生类
class Students implements Comparable{
private String name;
private int score;
public Students(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Students{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
@Override
public int compareTo(Object o) {
Students s = (Students)o;
if(s.score > ((Students) o).score){
return 1;
}else if(s.score == ((Students) o).score){
return 0;
}else{
return -1;
}
}
}
在 sort 方法中会自动调用 compareTo 方法.compareTo 的参数是 Object,其实传入的就是Students类型的对象,然后比较当前对象和参数对象的大小关系
接口间的承接
一个接口可以承接另一个接口,达到复用效果,使用 extends 关键字
接口间承接相当于把多个接口凭借在一起
Clonable 接口和深拷贝
Object 类中存在一个 clone 方法,调用这个方法可以创建一个对象的“拷贝”,但是想要合法的调用clone方法,必须先要实现 Clonable 接口,否则就会抛出 CloneNotSupportedException 异常
class Person implements Cloneable{
public String name;
public Person(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class TestDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("小明");
Person person2 = (Person) person1.clone();
person2.name = "小红";
System.out.println(person1);
System.out.println(person2);
}
}
如下代码即深拷贝:
class Money implements Cloneable{
public int m=10;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public String name;
public Money money ;
public Person(String name) {
this.name = name;
this.money = new Money();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.money = (Money) this.money.clone();
return person;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", money=" + money.m +
'}';
}
}
public class TestDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("小明");
Person person2 = (Person) person1.clone();
person2.name = "小红";
person2.money.m = 15;
System.out.println(person1);
System.out.println(person2);
}
}
感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!