title: Day03-Java面向对象上
date: 2020-05-26 16:21:56
author:子陌
举例:大象装冰箱
面向过程:
打开冰箱
存储大象
关闭冰箱
对于面向过程思想,强调的是过程(动作)典型语言代表:C语言
面向对象:
对于面向对象思想,强调的是对象(实体) 典型语言代表:C++、Java、C#
特点:
用Java语言描述生活中事务的行为,通过类的形式来体现。对于事物描述通常只关注两方面:一个是属性,一个是行为。
// 描述小汽车
/*
* 1、属性:轮胎数、颜色
* 2、行为:运行
*/
class Car{
int num = 1; // 显式初始化
String color; // 默认初始化
void run(){
// 当局部变量与成员变量同名时
int num = 10;
System.out.println(this.num + "..." + color);
}
}
class CarDemo{
public static void main(String[] args){
// 在计算机中创建Car实例,通过new关键字
Car bwm = new Car(); // bwm就是一个类类型的引用变量,指向了该类的对象
bwm.num = 4;
bwm.color = "red";
bwm.run(); // 使用对象中的内容,通过'.'成员的形式完成
Car c1 = new Car();
show(c1);
// 匿名对象:没有名字的对象。
new Car(); // 匿名对象。其实就是定义对象的简写格式。
// 1、当对象对方法进行一次调用的时候,就可以简化成匿名对象
new Car().run();
// 2、匿名对象可以当作实际参数进行传递
show(new Car());
}
// 汽车改装厂
public static void show(Car c){
// 类类型的变量一定指向对象。要不就是null
c.num = 3;
c.color = "black";
c.run();
}
}
成员变量和局部变量的区别:
成员变量定义在类中,整个类中都可以访问。
局部变量定义在函数,语句,局部代码块中,只在所属的区域有效。
成员变量存在于堆内存的对象中。
局部变量存在于栈内存的方法中。
成员变量随着对象的创建而存在,随着对象的消失而消失
局部变量随着所属区域的执行而存在,随着所属区域的结束而释放
成员变量都有默认初始化值。
局部变量没有默认初始化值。
class Person{
/*
* 人
* 属性:年龄
* 行为:说话
*/
int age;
void speak(){
System.out.println("age = " + age);
}
}
class Person1{
private int age; // 私有,权限修饰符,用于修饰成员,私有的内容只在本类中有效
public void setAge(int a){
if(a <= 0 && a > 130){
System.out.println("set age err");
return;
}
age = a;
speak();
}
void speak(){
System.out.println("age = " + age);
}
}
class PersonDemo{
public static void main(String[] args){
Person p = new Person();
p.age = -20; // 不符合逻辑
p.speak();
}
}
class Person{
private String name;
private int age;
// 定义一个Person构造函数 一构造就运行
Person(){
System.out.println("Person run");
}
public void speak(){
System.out.println("name" + name + ", age" + age);
}
}
class ConsDemo{
public static void main(String[] args){
Person p = new Person(); // 构造一个对象 可以给对象进行初始化
}
}
一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数。
如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。
一般函数和构造函数的区别:
构造函数:对象创建时,就会调用与之对应的构造函数,对对象进行初始化
一般函数:对象创建时,需要函数功能时才调用
构造函数:对象创建时,只会调用一次
一般函数:对象创建后,可以被多次调用
什么时候定义构造函数:
class Person{
private String name;
private int age;
Person(){
name = "zimo";
age = 1;
}
// 重载
Person(String n, int a){
name = n;
age = a;
}
// 重载
Person(int a, String n){
}
// 一般函数 构造函数没有返回值
void Person(){
name = "zimo";
age = 1;
}
public void speak(){
System.out.println("name" + name + ", age" + age);
}
}
class ConsDemo{
public static void main(String[] args){
Person p = new Person(); // 构造一个对象 可以给对象进行初始化
p.speak();
Person p1 = new Person("zang", 2);
p1.speak();
}
}
当成员变量和局部变量重名的时候,可以用关键字this来区分。
this:代表当前对象,this就是所在函数所属对象的引用(简单理解:哪个对象调用了this所在的函数,this就代表哪个对象)
this可以用于在构造函数中调用其他构造函数,其他一般函数不能调用构造函数。
注意:调用构造必须放在第一个,否则会错误,因为初始化动作必须先执行!
class Person{
private String name;
private int age;
Person(){
}
Person(String name){
this.name = name;
}
Person(String name, int age){
//this.Person(name);
this(name); // 调用上面那个构造函数Person(name) 如果想要调用构造必须放在第一个,否则会错误
this.age = age;
this.speak();
}
// 判断同龄人
public boolean compare(Person p){
/*if(this.age == p.age){
return true;
}else{
return false;
}*/
return this.age == p.age;
}
}
class Person{
String name; // 成员变量、实例变量
static String country = "CN"; // 静态变量、类变量
public void show(){
System.out.println(country + ":" + name);
System.out.println(Person.country + ":" + this.name); // 静态前面省略的是类名,不是this
}
}
class StaticDemo{
public static void main(String[] args){
Person p = new Person();
p.name = "zimo";
p.show();
System.out.println(p.country);
System.out.println(Person.country);
}
}
成员变量和静态变量的区别:
两个变量的生命周期不同:
成员变量随着对象的创建而存在,随着对象的被回收而释放;
静态变量随着类的加载而存在,随着类的消失而消失;
调用方式不同:
成员变量只能被对象调用;
静态变量可以被对象调用,还可以被类名调用;
别名不同:
成员变量也称为实例变量;
静态变量也称为类变量;
数据存储位置不同:
成员变量数据存储在堆内存的对象中,所以也叫对象特有数据;
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据
主函数的特殊之处
什么时候使用静态:
静态变量:
静态函数:
函数是否用静态修饰,参考一点该函数功能是否有访问到对象中特有的数据
简单理解,从源码角度,该功能是否需要访问非静态成员变量,如果有需要,该功能就是非静态的
如果不需要,就可以将该功能定义成静态的。当然也可以定义非静态,
但是非静态需要被对象调用,而仅创建对象没有访问特有数据的方法,该对象的创建没有意义
//静态代码块:用于给类进行初始化,有的类不需要创建对象
class StaticCode{
//构造代码块 不同的对象进行相同的操作 构造函数,不同的对象不同的操作
{
System.out.println("bbbbbbbbbbb"); // 构造一次执行一次
}
// 静态代码块只会执行一次
static{
System.out.println("hhhhhhhhhhhhh");
}
/*
void show(){
System.out.println("show run");
}*/
static void show(){
System.out.println("show run");
}
}
class StaticCodeDemo{
public static void main(String[] args){
// 局部代码块
{
System.out.println("111111");
}
//new StaticCode().show();
StaticCode.show();
// 输出结果:hhhhhhhhhhh show run
int[] arr = {
4,8,1,23,9};
int max = getMax(arr);
System.out.println(max);
}
public static int getMax(int[] arr){
int maxIndex = 0;
for(int i = 0; i < arr.length; i++){
if(arr[maxIndex] < arr[i])
maxIndex = i;
}
return arr[maxIndex];
}
}
/**
建立一个用于操作数组的工具类,其中包含着常见的对数组操作的函数如:最值,排序等。
@author zimo
@version V1.0
*/
public class ArrayTool{
private ArrayTool(){
} // 该类中的方法都是静态的,所以该类不需要创建对象,为了保证不让其他类创建该类对象,可以将该构造私有化
/**
获取整型数组的最大值
@param arr 接受一个元素为int类型的数组
@return 返回一个数组中最大的元素值
*/
public static int getMax(int[] arr){
int maxIndex = 0;
for(int i = 0; i < arr.length; i++){
if(arr[i] > arr[maxIndex]){
maxIndex = i
}
}
return arr[maxIndex];
}
/**
对数组进行选择排序
@param arr 接受一个元素为int类型的数组
*/
public static void selectSort(int[] arr){
for(int i = 0; i < arr.length - 1; i++){
for(int j = i + 1; j < arr.length; j++){
if(arr[i] > arr[j])
swap(arr,x,y);
}
}
}
/**
用于给数组进行元素的位置置换
@param arr 接受一个元素为int类型的数组
@param a 交换第1个数组元素下标
@param b 交换第2个数组元素下标
*/
// 私有功能不需要写文档注释,不会被javadoc识别,只需写单行,多行注释明确功能阅读性即可
private void swap(int[] arr, int a, int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
/**
获取指定的元素在指定数组中的索引
@param arr 接受一个元素为int类型的数组
@param key 要找到元素
@return 返回一个数组中第一次出现的位置,如果不存在返回-1
*/
public static int getIndex(int[] arr, int key){
for(int i = 0; i < arr.length; i++){
if(arr[x] == kay){
return i;
}
}
return -1;
}
/**
将int数组转换成字符串,格式是:[e1,e2,...]
@param arr 接受一个元素为int类型的数组
@return 返回该数组的字符串表现形式
*/
public static String arrayToString(int[] arr){
String str = "[";
for(int i = 0 ; i < arr.length; i++){
if(i != arr.length - 1)
str = str + arr[i] + ",";
else
str = str + arr[i] + "]";
}
return str;
}
}
javadoc [选项] [软件包名称] [源文件] [@file]
-d:输出到指定的目录下
javadoc -d ./myhelp -author -version ArrayTool.java
只有公共的类才能进行文档化(public class A{}),如果使用公共类,类名必须和文档名字一致
设计模式:对问题行之有效的解决方式。它是一种思想!
单例模式解决的问题:可以保证一个类在内存中的对象唯一性。
必须对于多个程序使用同一个配置信息对象时,就必须保证该对象的唯一性。
如何保证唯一性:
步骤:
// 单例模式 - 饿汉式
class Single{
// 类一加载,对象就已经存在了
static Single s = new Single(); // 如果不私有,外部类可以直接引用(类名.s)获取
private static Single s1 = new Single();
private Single(){
// 私有化构造,不允许外部类构造本类对象
}
public static Single getInstance(){
// 如果不做任何处理等价于 Single.s
return s;
}
public static Single getInstance1(String name){
if(name == "zimo")
return s1;
}
}
// 单例模式 - 懒汉式 (如果被多线程访问,可能无法保证唯一性,存在安全隐患)
class Single1{
// 类一加载,没有对象,只有调用getInstance方法时,才会创建对象
static Single1 s = null;
private Single1(){
// 私有化构造,不允许外部类构造本类对象
}
// 单例模式 延迟加载形式
public static Single1 getInstance(){
if(s == null)
s = new Single1(); // 获取的时候,才开始分配内存空间
return s;
}
}
class SingleDemo{
public static void main(String[] args){
// 这样实现实例不可控
Single ss = Single.getInstance(); // 如果不写条件 === Single ss = Single.s;
// 通过方法进行可控
Single sss = Single.getInstance(); // 通过方法获取单例可以保证唯一
}
}
继承的概述
Java中支持单继承,不能直接支持多继承,但对C++中的多继承机制进行改良。
单继承:一个子类只能有一个直接父类
class A{} class B extends A{}
多继承:一个子类可以有多个父类(Java中不允许,进行改良,通过"多实现"方式体现)
不直接支持,因为多个父类中有相同的成员,会产生调用的不确定性
class A{} class B{} class C entends A,B{}
Java支持多层(多重)继承:
class A{} class B extends A{} class C extends B{}
Java要使用一个继承体系时
class Person{
String name;
int age;
}
class Student extends Person{
/*单继承Person*/
void study(){
System.out.println(name + "is good good study, day day up" + age);
}
}
class Worker extends Person{
/*单继承Person*/
void work(){
System.out.println(name + "is worker")
}
}
继承的好处:
什么时候定义继承
当类与类之间存在所属关系的时候,就定义继承。例如xxx是yyy中的一种:xxx extends yyy
/*
* 在子父类中,成员的特点体现
* 1、成员变量
* 2、成员函数
* 3、构造函数
*/
class Fu{
int num1 = 4;
void showFuc(){
System.out.println("Fu!");
}
}
class Zi{
int num1 = 3;
int num2 = 5;
void show(){
System.out.println(num2 + ".." + num1); // 子类有不找父类 5 3 不写默认 this.num1
System.out.println(num2 + ".." + super.num1); // 子类有不找父类 5 4
}
void showFuc(){
System.out.println("zi!");
// super.showFuc(); // 如果想加上父类的功能就可以调用super关键字调用,否则子类递归
}
}
class ExtendsDemo{
public static void main(String[] args){
Zi z = new Zi();
z.show();
z.showFuc(); // "zi" 子类有不找父类
}
}
当本类成员和局部变量同名用this区分。
当子父类中的成员变量同名用super区分父类。
super关键字
this和super的用法很相似
函数覆盖
当子父类中出现成员同名函数,会运行子类的函数,这种现象称为覆盖。
函数两个特性:
覆盖注意事项:
什么时候使用覆盖操作:
当对一个类进行子类的扩展时,子类需要保留父类的功能声明
但是要定义子类中该功能的特有内容时,就是用覆盖操作完成
子类的实例化过程
final关键字
写法规范:常量所有字母都大写,多个单词,中间用_连接
// 继承的弊端:打破了封装性
final class Fu{
void method(){
// 调用底层的系统资源
}
}
class Fuu{
public static final double PI = 3.1415926; // 全局常量
final void method(){
// 调用底层的系统资源
}
void fun1(){
}
void fun2(){
}
}
/* final 类无法被继承
class Zi extends Fu{
void method(){System.out.println("hahaha");}
}*/
class Zi extends Fuu{
// final 修饰的方法无法被覆盖
// void method(){System.out.println("hahaha");}
}
class FinalDemo{
public static void main(String[] args){
// final 修饰的变量无法被修改
final int num = 9;
num = 10; // err 最终变量无法被修改
final int a; // err 最值变量必须初始化
}
}
抽象类
抽象:笼统、模糊、看不懂、不具体的东西
abstract class Demo{
// 抽象函数存在 类必须是抽象的
abstract void show();
}
class DemoA extends Demo{
void show(){
System.out.println("demoA show");
}
}
class DemoB extends Demo{
void show(){
System.out.println("demoB show");
}
}
特点:
方法只有声明没有实现,需要被abstract修饰,该方法就是抽象方法。
抽象方法必须定义在抽象类中,该类也必须被abstract修饰
抽象类不可以被实例化,因为调用抽象方法没有意义,没有方法体。
抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以实例化,否则这个子类还是抽象类
问题:
抽象类中有构造函数嘛?
有,用于子类对象进行初始化
抽象类可以不定义抽象方法嘛?
可以,但是很少见,目的就是不让该类创建对象。AWT的适配器对象就是这种类。
通常这个类有方法体,但是没有内容如:class Demo{ void show(){} void show1(){} }
抽象关键字不可以和哪些关键字共存?
private:子类抽象方法被隐藏,无法覆盖
static:如果是静态,就无需对象,可以直接运行,但是抽象类没有方法体
final:最终的和覆盖的矛盾,final修饰的无法重写和修改
抽象类和一般类的异同点?
相同点:
抽象类和一般类都是用来描述事物的,都在内部定义了成员
不同点:
抽象类一定是父类嘛?
是的,需要子类覆盖其方法后才可以后才可以对子类进行实例化
练习:
/*雇员示例:
需求:公司中程序员有姓名,工号,薪水,工作内容。
项目经理除了有姓名,工号,薪水,还有奖金,工作内容。
对给出需求进行数据建模。
*/
/*
分析:找出问题涉及对象,名词提炼法
程序员:
属性:姓名,工号,薪水
行为:工作
经理:
属性:姓名,工号,薪水,奖金
行为:工作
程序员和经理不存在直接继承关系,却具有共性内容,可以进行抽取,都是公司的雇员
可以将程序员和经理进行抽取,建立体系
*/
// 描述雇员
abstract class Employee{
private String name;
private String id;
private double pay;
Employee(String name, String id, double pay){
this.name = name;
this.id = id;
this.pay = pay;
}
public abstract void work();
}
// 描述程序员
class Programmer extends Employee{
Programmer(String name, String id, double pay){
super(name, id, pay);
}
public void work(){
System.out.println("doing code...");
}
}
// 描述经理
class Manager extends Employee{
private int bonus;
Manager(String name, String id, double pay, bonus){
super(name, id, pay);
this.bonus = bonus;
}
public void work(){
System.out.println("doing manager...");
}
}
接口
当一个抽象类中的方法都是抽象的时候,这时候可以将该抽象类用另一种形式定义和表示,就是接口interface
// 定义接口使用的关键字不是class, 是interface
interface Demo{
public static final int NUM = 4;
public abstract void show1();
public abstract void show2();
// 阅读性差的写法
public int BBB = 1; // 默认给你加上修饰符
void show2(); // 同样默认加上修饰符
}
class DemoImpl implements Demo{
public abstract void show1(){
}
public abstract void show2(){
}
}
class InterfaceDemo{
public static void main(String[] args){
DemoImpl d = new DemoImpl();
System.out.println(d.NUM);
System.out.println(DemoImpl.NUM);
System.out.println(Demo.NUM);
}
}
类与类之间是继承关系,类与接口之间是实现关系,接口与接口之间是继承关系且可以多继承
接口不能实例化,只能由实现了接口的子类并覆盖了接口的所有抽象方法才能进行实例化
interface A{
public abstract void show();
public abstract void showA();
}
interface B{
public abstract void show();
public abstract void showB();
}
// 多实现
class Test implements A, B{
// 多实现
public void show(){
// 既覆盖了A的show也覆盖了B的show
}
}
interface C{
public abstract void method(){
}
}
// 接口之间的多继承
interface D extends A,B,C{
}
// 继承另一个类的同时,还可以实现多个接口
class Test2 extends C implements A, B{
// 不能多继承但可以多实现,具备C的功能,还具备AB功能
public void show(){
// 既覆盖了A的show也覆盖了B的show
}
...
}
class InterfaceDemo{
public static void main(String[] args){
Test t = new Test();
t.show();
}
}
接口的特点:
接口与抽象类:
共性:都是不断抽取出来的抽象的概念
区别:
抽象类体现继承关系,一个类只能单继承
接口体现实现关系,一个类可以多实现
抽象类是继承,是"is a"的关系
接口是实现,是"like a"的关系
抽象类中可以定义非抽象方法,供子类直接使用
接口的方法都是抽象,接口中的成员都有固定修饰符
// 接口的应用
interface USB{
public abstract void open();
public abstract void close();
}
class BookPC{
public static void main(String[] args){
useUSB(new UDisk());
useUSB(new USBMouse());
}
// 接口类型的引用,用于接收(指向)接口的子类对象
public static void useUSB(USB u){
u.open();
u.close();
}
}
// 一年后换U盘
class UDisk implements USB{
public void open(){
System.out.println("uDisk open");
}
public void close(){
System.out.println("uDisk close");
}
}
// 鼠标
class USBMouse implements USB{
public void open(){
System.out.println("USBMouse open");
}
public void close(){
System.out.println("USBMouse close");
}
}
// 动物的多态性
class Animal{
abstract void eat();
}
class Cat extends Animal{
void eat(){
System.out.println("吃鱼");
}
void catchMouse(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal{
void eat(){
System.out.println("啃骨头");
}
void lookHome(){
System.out.println("看家");
}
}
class DuoTaiTest{
public static void main(String[] args){
System.out.println("HelloWorld!");
Cat c = new Cat();
c.eat();
Dog d = new Dog();
d.eat();
/*
猫这类事物即具备猫的形态,又具备动物的形态
这就是对象的多态性
简单理解:就是一个对象对应不同的类型
*/
Cat cat = new Cat();
Animal cat1 = new Cat(); // 一个对象,两种形态
/
Animal cat = new Cat(); // 自动提升类型,但是特有功能无法访问,限制特有功能的访问
Animal dog = new Dog(); // 向上转型
method(cat);
method(dog);
method(new Dog());
// 如果还想用具体动物的特有功能,可以将该对象向下转型
Cat c = (Cat)cat; // 向下转型是为了使用子类特有的方法
c.catchMouse(); // “抓老鼠”
Dog dg = (Dog)cat; // ClassCastException 猫不能转换成狗
}
public static void method(Animal a){
a.eat();
}
}
注意:对于转型,自始至终都是子类对象在做着类型的变化
多态的好处:
提高了代码的扩展性,前期定义的代码可以使用后期的内容
多态的弊端:
前期定义的内容不能使用(调用)后期子类的特有内容
多态的前提:
多态 - 类型判断instanceof
// 动物的多态性
class Animal{
abstract void eat();
}
class Cat extends Animal{
void eat(){
System.out.println("吃鱼");
}
void catchMouse(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal{
void eat(){
System.out.println("啃骨头");
}
void lookHome(){
System.out.println("看家");
}
}
class Test{
public static void method(Animal a){
method(new Cat());
method(new Dog());
}
public static void method(Animal a){
a.eat();
// instanceof:用于判断对象的具体类型,只能用于引用类型判断,通常用于健壮性的判断
if(a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse();
}else if(a instanceof Dog){
Dog d = (Dog)a;
d.lookHome();
}
}
}
Fu f = new Zi();
Fu f = new Zi();
介绍 (Introduction)If you are actively developing an application, using Docker can simplify your workflow and the process of deploying your application to production. Working with containers in develo...
学习链接:100道MySQL常见面试题总结写给 Java 程序员的 24 个MySQL面试题,拿走不谢!写给 Java 程序员的 24 个MySQL面试题,拿走不谢! 转MySQL经典面试题玩转Mysql系列 - 第24篇:如何正确的使用索引?...
FC-SAN和IP-SAN两者的优缺点分别是什么?一般来说,企业在面临iSCSI SAN存储解决方案时,多半喜欢拿FC SAN及NAS与其做一番比较。在此先就FC与iSCSI做一比较,基本两者同属走Block协议的SAN架构,只不过前者透过光纤,后者藉由IP传输数据罢了,而两者在管理及应用上也大同小异,其间只不过优劣好坏的差异。至于SAN与NAS的差异而言,笔者走访了...
node安装及环境变量配置
说说高斯过程回归作者介绍:新浪微博ID @妖僧老冯, 9月将赴南京大学(直博生),方向是机器学习与数据挖掘编者:小便和作者打过几次交道,一直以为是他是已“修成正果”的某某博士,便“毕恭毕敬”地去邀请他写篇牛文。细聊之后才得知小伙子原来是90后,9月份才博士入学。这篇文章对GP进行了深度科普,数学公式是有一些的,但耐心读读,都不是问题的。高斯过程是机器学习领域一个基础的方法,同时又和其他方法...
一、爬虫部分爬虫说明:1、本爬虫是以面向对象的方式进行代码架构的2、本爬虫爬取的数据存入到MongoDB数据库中3、爬虫代码中有详细注释4、爬虫爬取的美食是以无锡为例代码展示import jsonimport reimport timefrom pymongo import MongoClientimport requestsfrom lxml import htmlclass MeituanSpider(): def __init__(self): #
java的基本特征1.简单Java最初是为对家用电器进行集成控制而设计的一种语言,因此它必须简单明了。Java语言的简单性主要体现在以下三个方面:Java的风格类似于C++,因而C++程序员是非常熟悉的。从某种意义上讲,Java语言是C及C++语言的一个变种,因此,C++程序员可以很快就掌握Java编程技术。Java摒弃了C++中容易引发程序错误的地方,如指针和内存管理。Ja...
安装Roboguide软件的详细步骤
node-webkit中使用sqlite3sqlite3的官方文档提到:nodejs和node-webkit的ABI不同,所以通过npm install sqlite3下载的sqlite3是无法使用的,需要重新编译。windows编译:以LTS版本(0.14.7)为例一、所需编译环境安装Python 2.7.14(不支持3.x版本)并设置好环境变量,下载地址:https://www.python.org/downloads/ 安装最新的nodejs+npm 下载地址:https...
题目链接:http://acm.hust.edu.cn/vjudge/problem/51191题意:给一个字符串,相同部分可以折叠,折叠可以嵌套。求最短长度的一种折叠方法。括号和数字的长度也要考虑进去。思路:对于一个字符串,有三种策略:1、不折叠。2、本身可以折叠。3、分为两个区间子问题。#include #include #include #inclu