面向对象
初识面向对象
面向过程&面向对象
面向过程思想: 步骤清晰简单,第一步做什么,第二步做什么…
面对过程适合处理一些较为简单的问题
面向对象思想 : 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,
然后对这些类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
什么是面向对象
- 面向对象编程
(Object-Oriented Programming ,OOP)
- 面向对象编程的本质就是:以类的方式组织代码,以对象的方式组织(封装)数据。
- 核心思想:抽象
- 三大特性:封装、继承、多态
- 从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象
- 从代码运行角度考虑是先有类后有对象。类是对象的模板。
方法回顾和加深
回顾方法的定义
public class Dome01{
//public类的名字应该和java文件名相同
public static void main(String[] args){
}
//方法名应该见名知意,驼峰原则
//参数列表 (参数类型,参数名)...
/*
修饰符 返回值类型 方法名(形参){
//方法体
return 返回值;//void 不返回值 return;
}
*/
public static int getMaxNum(int a,int b){
return a>b ? a : b;
}
public static String getHelloWorld(){
return "hello,world";
}
public void readFile(String file) throws IOException{
}
}
回顾方法的调用
静态与非静态
静态方法 static调用时类名+方法名
非静态方法调用需要实例化。
//跨文件(类)调用
Student.say();//静态方法
//非静态方法
Student stu = new Student();
stu.say();
//在同一个文件(类)中
//非静态可以相互调用,静态也可以相互调用,但静态不可以调用非静态的,非静态可以调用静态的
值传递与引用传递
//值传递
public static void main(String[] args) {
int a = 1;
System.out.println(a);
change(a);
System.out.println(a);
// 1
// 1
}
public static void change(int a){
a = 10;
}
//引用传递:对象,本质还是值传递.有点像指针
public class hello {
public static void main(String[] args) {
Person aaa = new Person();
System.out.println(aaa.name);
change(aaa);
System.out.println(aaa.name);
}
}
public static void change(Person person){
person.name = "tiangong";
}
对象的创建分析
类与对象的关系
-
类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物。
动物、植物、手机、电脑…
Person类、Pet类、Car类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为
-
对象是抽象概念的具体实例
张三就是人的一个具体实例,张三家里的旺财就是狗的一个具体实例。
能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。
创建和初始化对象
- 使用new关键字创建对象
- 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
//this是实例本身,哪个实例调用,this就指哪个实例
//快捷键 new 类名.var 加回车
//一个项目应该只存在一个main方法。
//一个java文件只能有一个public类
//对象是类的实例
public class Dome01 {
public static void main(String[] args) {
Cat mimi = new Cat();
Cat dajv = new Cat();
mimi.name = "咪咪";
dajv.name = "大橘";
mimi.bark();
dajv.bark();
}
//换文件,或者把下面这个类的public修饰去掉
public class Cat{
//属性,字段
String name;
int age;
//方法(行为)
public void bark(){
System.out.println(this.name+ " :喵~ 喵~~~~");//这里加不加this好像都好使的
}
}
构造器详解
当我们开了一个新的空的class Person类,但我们依然可以new出来一个对象。
从class文件中看,一个类即使什么都不写,它也会存在一个方法,这就是构造方法,也叫构造器
-
类中的构造器也称为构造方法,是在进行创建对象的时候必须调用的。并且构造器有以下两个特点:
必须和类的名字相同
必须没有返回类型,也不能写void -
构造器必须要掌握
class Person{ String name; //构造器的作用 //1.使用new关键字,本质实在调用构造器 //2.实例化初始值. public Person(){ this.name = "天工"; } //有参构造,一旦定义了有参构造,无参就必须显示 public Person(String name){ this.name = name; } } //另一边的main方法 Person R = new Person("RockMusic"); System.out.println(R.name);
idea快捷键:alt + insert 生成构造器
然后选Constructor.接下来选OK为有参,选Select None为无参
创建对象内存分析
新的对象可以直接从静态方法区调用方法。
面向对象三大特性
封装
- 该显的显,该藏的藏。
- 我们程序设计要追求“高内聚,低耦合”。
高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅暴露少量的方法给外部使用。
- 封装(数据的隐藏)
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。 - 记住这句话就够了:1.属性私有 2. get/set
//不知道为什么,一个文件里,能有除public class之外的两个class.
//属性私有
class Student{
private String name;
private int age;
}//这个样子,就不允许更改新创建出来的对象的属性
// getter / setter
//提供一些可以操作这个属性的方法
//提供一些public的get、set方法
//get 获得这个数据
//set 设置这个数据
class FreshMan{
private String name;
private int age;
public String getName(){
return name;
}
public void setName(String N){
name = N;
}
//idea 有快捷键 alt + insert.选择getter and setter,再选择属性,点ok.
public int getAge() {
return age;
}
public void setAge(int age) {
//对于年龄而言,-1岁和过大的岁数是不符合实际情况的,所以施加判断
if(age>120 || age<0){
System.out.println("输入的年龄不合法");
}else{
this.age = age;
}
}
}
//main这边
FreshMan y = new FreshMan();
y.setName("hhh") ;
System.out.println(y.getName());
封装的优点:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 增加系统的可维护性
继承
-
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模.
-
extends的意思是“扩展”。子类是父类的扩展。
-
JAVA中类只有单继承,没有多继承! 一子只一父,一父可多子。
-
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
-
继承关系的俩个类,一个为子类(派生类),一个为父类(基类)。
-
子类继承父类,使用关键字extends来表示。
在Java中,所有的类都默认直接或者间接继承Object类(始祖) -
子类和父类之间,从意义上讲应该具有"is a"的关系.
// 子类可以继承父类的default及以上的的属性和方法。私有的东西只能隐式继承,不能调用。
// public 公共的
// protected 受保护的
// default 默认
// private 私有
public class Person {
String name;
protected String myName = "明月";
int age;
String sex;
public void shoot(){
System.out.println(this.name + "说:大梦平生");
}
public void print(){
System.out.println("Person");
}
public String getName(){
return name;
}
public void setName(String N){
this.name = N;
}
public int getAge() {
return age;
}
public class YoungMan extends Person{
public void shoot(){
System.out.println(this.name + "说:潜龙毋用");
}
}
public class OldMan extends Person{
}
public class Me extends Person{
private String myName = "清风";
public void test(String n){
System.out.println(this.myName);
System.out.println(super.myName);
System.out.println(n);
}
public void print(){
System.out.println("Me");
}
public void test2(){
print();
this.print();
super.print();
}
}
public class hello {
public static void main(String[] args) {
YoungMan child = new YoungMan();
child.setName("小孩");
child.setAge(10);
child.shoot();
OldMan theOld = new OldMan();
theOld.setName("耄耋");
theOld.shoot();
Me mySelf = new Me();
mySelf.test("我");
mySelf.test2();
}
}
//小孩说:潜龙毋用
//耄耋说:大梦平生
//清风
//明月
//我
//Me
//Me
//Person
子类创建一个对象是,先调用父类构造方法,再调用子类构造方法。//super(); 子类方法();
所以调用父类构造器,必须要在子类构造器的第一行
super注意点
- super调用父类的构造方法,必须在构造方法的第一个
- super 必须只能出现在子类的方法或者构造方法中!
- super和 this不能同时调用构造方法!(因为super();和this();都必须在第一行)
this VS super
- 代表的对象不同:
- this:本身调用者这个对象
- super:代表父类对象的
- 应用前提
- this:没有继承也可以使用
- super:只能在继承条件才可以使用
- 构造方法
- this();本类的构造
- super():父类的构造
重写
重写是方法的重写,和属性无关
public class B {
public static void test(){
System.out.println("B");
}
}
public class A extends B{
public static void test(){
System.out.println("A");
}
}
public class C {
public static void main(String[] args) {
//静态方法调用只和左边,定义的数据类型有关
A a = new A();
a.test(); //A
// 父类的引用指向了子类
B b = new A();
b.test(); //B
}
}
//再写一下A
public class A extends B{
//快捷键,alt + insert 点override methods
@Override //这是一个注解,有功能的注释
public void test(){
super.test();
}
}
//然后我们修改内容
public class A extends B{
@Override
public void test(){
System.out.println("A");
}
}
//再运行时,都变成了A
//所以静态方法和非静态方法不一样
//非静态 :重写
重写:需要有继承关系.子类重写父类的方法!
特点:
-
方法名必须相同
-
参数列表列表必须相同
-
修饰符:范围可以扩大但不能缩小 Public>Protected>Default>Private
-
抛出的异常:范围,可以被缩小,但不能扩大;
Exception(大) -->ClassNotFoundException
重写,子类的方法和父类必要一致;方法体不同!
为什么需要重写?
- 父类的功能,子类不一定需要,或者不一定满足!
快捷键: Alt + Insert ; ( override;)
java
的访问权限
public : 对所有类可见。使用对象:类、接口、变量、方法
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
多态
- 即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
- 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
- 多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
- 注意:多态是方法的多态,属性没有多态性。
instanceof
引用类型的类型转换
//一个对象的实际类型是确定的
//但指向的引用类型是不确定的:父类的引用指向子类。
YoungMan s1 = new YoungMan();//子类能调用的方法都是自己的或者继承子类的。
Person s2 = new YoungMan();//父类,可以指向子类,但是不能调用子类独有的方法
Object s1 = new YoungMan();
//对象能执行哪些方法,主要看对象左边的类型,和右边关系不大。
//子类重写了父类的方法,就会执行子类的方法。
//举个例子,YoungMan里有非静态方法,走和爬
//Person 里只有非静态方法,走
s1.crawl();//可执行
s2.crawl(); //不可执行
((YoungMan) s2).crawl();// 强制类型转换 可执行
多态注意事项
- 多态是方法的多态,属性没有多态
- 父类和子类,有联系。如果没有关系转换,会报错类型转换异常!
CLassCastException
- 存在条件:继承关系,方法需要重写,父类引用指向子类对象!
Father f1 = new Son();
不能重写的方法
- static 方法,属于类,不属于实例。
- final 常量
- private方法
instanceof
boolean result = obj instanceof Class;
其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错(编译不通过),如果不能确定类型,则通过编译,具体看运行时确定。
/* 放一下各个类的关系,作为前提条件
Object > String
Object > Person > Teacher
Object > Person > Student
*/
Object obj = new Student();
System.out.println(obj instanceof Student);//true
System.out.println(obj instanceof Person);//true
System.out.println(obj instanceof Object);//true
System.out.println(obj instanceof Teacher);//false
System.out.println(obj instanceof String);//false
Person ren = new Student();
System.out.println(ren instanceof Student);//true
System.out.println(ren instanceof Person);//true
System.out.println(ren instanceof Object);//true
System.out.println(ren instanceof Teacher);//false
//System.out.println(ren instanceof String);编译报错
Student stu = new Student();
System.out.println(stu instanceof Student);//true
System.out.println(stu instanceof Person);//true
System.out.println(stu instanceof Object);//true
//System.out.println(stu instanceof Teacher);//编译报错
// System.out.println(stu instanceof String);//编译报错
编译器检查是看引用类型,运行结果是看引用对象的实际类型。即编译能否通过看左边引用类型说明,运行结果看右边实际对象构造。
类型转换
public class Application {
public static void main(String[] args) {
//类型转换 父 子
//高 <--------- 低
Person wuhu = new Student(); //自动向上类型转换
wuhu.run(); //调用父类方法
//obj.say(); 向上类型转换丢失子类的方法
((Student) wuhu).say();//父类转化为子类,强制向下类型转换
((Student) wuhu).run();//子类可以调用父类的方法
}
多态小结:
- 父类引用指向子类的对象
- 把子类转换为父类,自动向上类型转换,会丢失子类自己的方法。
- 把父类转换为子类,向下类型转换,强制转换,可以调用父类的方法。
- 方便方法的调用,减少重复的代码,简洁。
static
public class Student {
private static int age;
private double score;
public void run(){
}
public static void go(){
}
public static void main(String[] args) {
Student ming = new Student();
System.out.println(ming.age);
System.out.println(ming.score);
System.out.println(Student.age);//静态属性可以通过 类.属性 直接调用
//System.out.println(Student.score); 编译出错
//非静态方法的使用,必须new 一个对象出来
ming.run();
//Student.run(); 编译出错
new Student().run();
Student.go();
go(); //静态方法可以直接调用,或者用 类.方法 调用
}
}
代码块
public class Rubbit {
{
//匿名代码块
//可以用来赋初值
System.out.println("匿名代码块");
}
static {
//静态代码块
//最先执行,且只执行一次
System.out.println("静态代码块");
}
public Rubbit() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Rubbit r = new Rubbit();
System.out.println("==================");
Rubbit amiya = new Rubbit();
}
}
/*
静态代码块
匿名代码块
构造方法
==================
匿名代码块
构造方法
*/
静态导入包
我们使用random()的时候
得这么写
Math.random();
如果想直接写random()
的话,需要静态导入包
import static java.lang.Math.random;
坚持住,今天做的,虽然辛苦,可这是我送给未来的礼物
抽象类和接口
欢迎来到抽象类
- abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。
- 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
- 抽象类,不能通过使用new关键字来创建对象,它是用来让子类继承的。
- 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
看弹幕说:比如你弄一个人物抽象类,有抽象的身高体重,容貌,然后不断弄子类继承,变成新人物,身高,体重,容貌你自己定,还可以加点别的东西。有点像求职模板,空白的自己往里填,不像的地方是可以自己往里加其他东西。
public abstract class Action {
//abstract ,抽象方法,只有方法名字,没有方法的实现。
public abstract void doSomething();
//不能new抽象类,只能靠子类去实现它
//抽象类中可以有普通方法
//但抽象方法必须在抽象类中
}
//抽象类的所有方法,继承了它的子类,都必须要实现它的方法,除非它的子类也是
//抽象类,那就用子子类来实现
public class A extends Action{
@Override
public void doSomething() {
}
}
欢迎来到接口
(听弹幕说:接口的默认和静态方法没说,等我看看书,以后再补吧)
- 普通类:只有具体实现
- 抽象类:具体实现和规范(抽象方法)都有!
- 接口:只有规范!自己无法写方法,专业的约束!约束和实现分离:面向接口编程
理解
- 接口就是规范,定义的是一组规则,体现了现实世界中”如果你是…则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你勇者,则必须扒出圣剑,打败魔王;如果你是程序员,则必须会编程。
- 接口的本质是标准,就像我们人间的法律一样。制定好后大家都遵守。
- 面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++、java、c等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
- 声明类的关键字是class,声明接口的关键字是interface
作用
- 约束--->标准
- 定义一些方法,让不同的人实现
- public abstract 方法
- public static final 常量
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口
- 实现了接口的类,必须要重写接口中的方法
public interface UserService {
//接口中的所有方法的定义其实都是抽象的,省略了public abstract
//属性是默认为 常量 public static final
//但好像不怎么用属性
public static final int age = 99;
void add(String name);
void delete(String name);
void change(String name);
void get(String name);
}
public interface TimeService {
void timer();
}
//类可以实现接口 implements 接口
//实现了接口的类,就需要重写接口中的方法。
//多继承,利用接口实现多继承
public class Servicelmpl implements UserService,TimeService{
//快捷方式 alt + insert 选择implement Mthods
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void change(String name) {
}
@Override
public void get(String name) {
}
@Override
public void timer(){
}
}
内部类
内部类(此处仅作了解)
内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。
成员内部类、静态内部类、局部内部类、匿名内部类
成员内部类
public class Outer {
private int id;
public void out(){
System.out.println("这是外部类的方法");
}
public class Inner{
public void in(){
System.out.println("这是内部类的方法");
Outer.this.out();
//内部类可以通过 外部类类名.this.外部类方法,调用外部方法
}
public void getID(){
//内部类可以调用外部类的属性
System.out.println(id);
}
}
}
public class HI {
public static void main(String[] args) {
Outer o = new Outer();
//通过这个外部类来实例化内部类
Outer.Inner i = o.new Inner();
i.in();
i.getID();
}
}
静态内部类
//内部类可以访问外部static属性,但static的内部类不能访问非静态的外部属性
//同时,这边没办法弄内部类对象了,以后再说,浅浅的了解一下
public class Outer {
private static int id;
public void out(){
System.out.println("这是外部类的方法");
}
public static class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
public void getID(){
System.out.println(id);
}
}
}
局部内部类
public class Outer{
public void methods(){
class Inner{
public void in(){
}
}
}
}
匿名内部类
public class Test {
public static void main(String[] args) {
//没有名字初始化类,不用把实例保存在变量中
new Apple().eat();
}
UserService userService = new UserService() {
@Override
public void hello() {
}
}
}
class Apple{
public void eat(){
System.out.println("eat an apple");
}
}
interface UserService{
void hello();
}
标签:Java,子类,void,System,面向对象,println,public,out
From: https://www.cnblogs.com/tiangong/p/16731970.html