面向对象学习笔记
-
所谓面向对象,其实就是分析问题时,以问题所涉及到的事或物为中心的分析方式
-
内存空间存储内容:栈(方法、变量),堆(对象),元空间/方法区(类的信息)
-
类表示归纳和整理,对象就表示具体的事物
类的语法结构:
class 类名 { 特征(属性); 功能(方法); }
创建对象的语法结构:
new 所创建对象类型();
-
先声明类
-
创建对象
-
声明属性,所谓的属性其实就是类中的变量
变量类型 变量名称 = 变量值
属性类型 属性名称 = 属性值
-
声明方法
void 方法名(参数){ 功能代码 }
-
执行方法
对象.方法名()
-
总结:
声明 class 类名 { // 属性(0个或多个) 类型 名称 = 值 // 方法(行为,0个或多个) void 方法名(){ 逻辑代码 } } 使用 构建对象:new 类名() 访问属性:对象.属性名 访问方法:对象.方法名()
-
-
类:结构体,里面包含了属性(特征)和方法(行为),会有很多对象,class:关键字(全是大小写),类名:类的名称,标识符。遵循规则,一般情况下,类名的首写字母是大写。对象:类的实例化(具象化)。
-
new 类名()
new也是关键字,表示创建一个具体的对象,而且使用一次,创建一次,每次都是全新的。一般new出来的对象会赋值给变量,方便重复使用,变量的类型就是对象的类型。对象是将内存地址赋值给了变量,所以变量其实引用了内存中的对象,所以称之为引用变量,而变量的数据类型称之为引用数据类型。
-
面向对象 - 属性
-
所谓的属性,其实就是类的对象的相同特征
-
语法和变量的声明很像
-
属性类型 属性名称 = 属性值
-
如果在声明属性的同时进行了初始化赋值,那么所有对象的属性就完全相同
-
所以如果希望每个对象的属性不一致,那么可以不用在声明属性的时候进行初始化
-
如果属性会在构造对象的时候默认初始化,而默认初始化的值取决于属性的类型:
byte,short,int,long => 0; float,double => 0.0; boolean flag = false; char = 空字符; 引用数据类型 => null
-
变量的作用域非常小,只在当前的大括号内有效
-
属性不仅仅在当前类中有效,而且可以随着对象在其它地方使用
-
变量使用前必须初始化,否则会出现错误,属性可以不用初始化,因为JVM会帮助我们自动完成初始化。
-
-
面向对象 - 方法
- 声明语法:void 方法名(){ 逻辑代码 }
-
声明语法(补充):[方法的返回值类型] [void] 方法名(){ 逻辑代码 }
- 方法的调用方式:对象.方法名()
-
面向对象 - 方法参数
-
使用外部数据控制方法内部实现的操作,使用的是参数语法实现,也叫方法参数
语法:方法名( 参数类型 参数名称 )
语法:方法名( 参数类型1 参数名称1, 参数类型2 参数名称2 )
-
当传递多个参数时,需要注意:
1.参数个数需要匹配
2.参数类型需要匹配
3.参数顺序需要匹配
4.当参数的个数不确定时。但是类型相同时,可以采用特殊的参数语法声明:可变参数。(语法:参数类型… 参数名称)(如果参数中还包含其他含义的参数,那么可变参数应该声明在最后;打印多个参数时需要按照数组的方式打印出来)
-
-
面向对象 - 方法参数 - 传值方式
例1:
public class Java01_Object_Method_Param_1 { public static void main(String[] args) { //TODO 面向对象 - 方法 - 参数 int i = 10; test(i); System.out.println(i); } public static void test(int i) { i = i + 10; } }
结果:
10
main方法中的i=10,执行新方法test时,将main压栈,test中i执行i=i+10,i的值为20,当test方法执行完毕后,将其弹栈,然后main方法执行打印操作时,打印的结果是10。
例2:
public class Java01_Object_Method_Param_1 { public static void main(String[] args) { //TODO 面向对象 - 方法 - 参数 String s = "abc"; test(s); System.out.println(s); } public static void test(String s) { s = s + 10; } }
结果:
abc
main方法中的s=“abc”,(abc为引用类型,需要在堆中进行),main方法指向堆中的“abc”,然后执行新方法test时,将main压栈,test中的s执行s=s+10,s的值为“abc10”,test指向堆中的“abc10”,test方法执行结束后,将test方法弹栈,此时main执行打印操作,结果为“abc”。
例3:
public class Java01_Object_Method_Param_1 { public static void main(String[] args) { //TODO 面向对象 - 方法 - 参数 User user = new User(); user.name = "zhangsan"; test(user); System.out.println(user.name); } public static void test(User user){ user.name = "lisi"; } } class User{ String name; }
结果:
lisi
main方法中的user.name = “zhangsan”,执行test方法,test方法也指向堆中的user对象,执行user.name = "lisi"后,user对象的name属性值变为lisi,test方法弹出栈,执行main方法中的打印操作,所以结果为lisi。
总结:
Java中方法参数的传递为值传递
基本数据类型:数值
引用数据类型:引用地址
-
面向对象 - 静态
- 针对于具体对象的属性称之为对象属性,成员属性,实例属性
- 针对于具体对象的方法称之为对象方法,成员方法,实例方法
- 把和对象无关,只和类相关的称之为静态,和类相关的属性成为静态属性,和类相关的方法称之为静态方法
-
先有类,再有对象
public class Java01_Object_Static { public static void main(String[] args) { //TODO 先有类,后有对象 Test t = new Test(); t.test(); t.test1(); Test.test1(); } } class Test { String name; static String sex; void test(){ System.out.println("test..."); } static void test1(){ System.out.println("test1..."); } }
结果:
test... test1... test1...
先有类再有对象,有对象就意味着一定有类,且成员方法里面可以调用静态方法,总结一下就是对象不仅可以访问成员属性和成员方法,还可以访问静态属性和静态方法,但是静态方法不能访问成员属性和成员方法。
-
面向对象 - 静态代码块
public class Java01_Object_Static_01 { public static void main(String[] args) { //TODO 面向对象 - 静态 User08.test(); } } class User08 { static { //静态代码块 System.out.println("静态代码块执行"); } static void test() { System.out.println("test..."); } }
结果:
静态代码块执行 test...
类的信息加载完成后,会自动调用静态代码块,可以完成静态属性的初始化功能。(对象准备创建时,也会自动调用代码块,但不是静态的)
-
面向对象 - Package - 包
package中容纳类,基本语法:package 包的完整路径; 路径中的多个包使用点隔开。
主要功能用于分类管理。
一个类可以没有包,但是package不可以在同一个源码文件中使用多次。
包名为了区分类名,所以一般全部都是小写。
Java中存在不同包的相同名称的类,可以使用包进行区分。
一般情况下,在使用类的情况下,我们
-
都会使用类的全名(包名 + 类型) (new java.util.Date();)
-
面向对象 - Import
java.lang在Java代码中不用写,Java虚拟机自动添加,其它包要写。
Java中提供import语法进行导包。
快捷键alt+enter自动导包。
import语句只能使用在package后,class前。
import关键字可以多次使用,导入多个类。
如果同一个包需要导入大量的类,那么可以使用通配符*来简化操作。
如果import不同包中相同的类,那么还是需要在使用时增加包名。
如果import相同包中的不同类,那么不需要再次导入包名。
-
面向对象 - 构建对象
User user = new User();
括号代表一种特殊的方法,构造方法:专门用于构建对象。
如果一个类中没有任何的构造方法,那么JVM会自动添加一个公共的,无参的构造方法,方便对象的调用。
基本语法:类名(){}
1.构造方法也是方法,但是没有void关键字
2.方法名和类名完全相同
3.如果类中没有构造方法,那么JVM会提供默认的构造方法
4.如果类中有构造方法,那么JVM不会提供默认的构造方法
5.构造方法也是方法,所以也可以传递参数,但是一般传递参数的目的是用于对象属性的赋值。
6.代码块是在构造对象之前执行的
public class Java01_Object_Instance { public static void main(String[] args) { //TODO 面向对象 - 构建对象 User11 user = new User11("zhangsan"); user.test(); } } class User11{ String username; { System.out.println("代码块1"); } User11(String name){ System.out.println("user..."); username = name; } { System.out.println("代码块2"); } void test(){ System.out.println("test..."); } { System.out.println("代码块3"); } }
结果:
代码块1 代码块2 代码块3 user... test...
-
面向对象 - 继承
面向对象中有3个非常重要的特征:继承、封装、多态。
类存在父子关系,子类可以直接获取到父类的成员属性和成员方法。
类的继承只能是单继承,一个类只能有一个父类,不能存在多个父类。
一个父类可以有多个子类。
public class Java01_Object_Extends { public static void main(String[] args) { Child c = new Child(); System.out.println(c.name); c.test(); } } class Parent{ String name = "zhangsan"; void test(){ System.out.println("test"); } } class Child extends Parent{ }
结果:
zhangsan test
如果父类和子类含有相同的属性,可以采用特殊关键字进行区分。
supper:上一级;this:当前; this.name可以省略为name
public class Java01_Object_Extends_1 { public static void main(String[] args) { Child1 c = new Child1(); //System.out.println(c.name); c.test(); } } class Parent1{ String name = "zhangsan"; } class Child1 extends Parent1 { String name = "lisi"; void test(){ System.out.println(super.name); System.out.println(this.name); System.out.println(name); } }
结果:
zhangsan lisi lisi
-
父类对象是在子类对象创建前创建完成的,创建子类对象前会调用父类的构造方法完成父类的创建;
默认情况下,子类对象构建时,会默认调用父类的构造方法完成父类对象的创建,使用的是super的方式,只不过JVM会自动完成;
如果父类提供构造方法,那么JVM不会提供默认的构造方法,那么子类应该显式调用super方法构建父类对象。
public class Java01_Object_Extends_2 { public static void main(String[] args) { //TODO 面向对象 - Extends - 继承 // 构造方法 Child2 c1 = new Child2(); Child2 c2 = new Child2(); Child2 c3 = new Child2(); } } class Parent2 { Parent2() { System.out.println("parent"); } } class Child2 extends Parent2 { Child2() { System.out.println("child..."); } }
结果:
parent child... parent child... parent child...
修正和补充:
new:只会构建一个对象;
先构建对象,再开辟内存空间,再执行构造方法;
构造方法的主要目的是为了完成内存空间对象属性的初始化操作。
-
面向对象 - 多态
所谓的多态,其实就是一个对象在不同场景下表现出来的不同状态和形态;
多态语法其实就是对对象的使用场景进行了约束;
一个对象可以使用的功能取决于引用变量的类型;
子类在使用父类进行创建对象时只能调用父类的属性和方法,只有在使用自己进行对象创建时才能使用父类和子类的属性和方法,对象的使用场景和方法受到了限制。
-
面向对象 - 方法重载
一个类中,不能重复声明相同的方法,也不能声明相同的属性,这里相同的方法指的是方法名,参数列表相同,和返回值类型无关;
如果方法名相同,但是参数列表(个数,顺序,类型)不相同,会认为是不同的方法,只不过名称一样,这个操作在Java中称之为方法的重载;
public class Java02_Object { public static void main(String[] args) { User02 user = new User02(); user.login(1111); user.login("123123"); user.login("zhangsan","123456"); } } class User02 { void login(String account, String password){ System.out.println("账号,密码登录"); } void login(int tel){ System.out.println("手机验证码登录"); } void login(String wx){ System.out.println("微信、支付宝登录"); } }
结果:
手机验证码登录 微信、支付宝登录 账号,密码登录
构造方法也存在方法的重载:
public class Java03_Object { public static void main(String[] args) { User03 user = new User03(); User03 user1 = new User03("zhangsan"); } } class User03 { User03() { System.out.println("user..."); } User03(String name) { System.out.println("user..." + name); } }
结果:
user... user...zhangsan
如果在一个构造方法中,想要调用其他的构造方法,那么需要使用特殊的关键字:this,等同于new语句。
public class Java03_Object { public static void main(String[] args) { User03 user1 = new User03(); //User03 user2 = new User03("zhangsan"); //User03 user3 = new User03("zahngsan","男"); } } class User03{ User03() { this("zhangsan"); } User03(String name) { this(name,"男"); } User03(String name, String sex) { System.out.println(name + "," + sex); } }
结果:
zhangsan,男
byte => 8, short => 16, char => 16, int => 32, long =>32(32位系统), long =>64(64位系统), long long => 64, float => 32, double => 64;
基本数据类型在匹配方法时,可以在数值不变的情况下,扩大数据的精度;
public class Java04_Object { public static void main(String[] args) { byte b = 10; test(b); } // static void test(byte b) { // System.out.println("bbb"); // } static void test(short s) { System.out.println("sss"); } static void test(char c) { System.out.println("ccc"); } static void test(int i) { System.out.println("iii"); } }
结果:
sss
byte类型无法和char类型做转换,char没有负数,但是byte存在负数;
public class Java04_Object { public static void main(String[] args) { byte b = 10; test(b); } // static void test(byte b) { // System.out.println("bbb"); // } // static void test(short s) { // System.out.println("sss"); // } static void test(char c) { System.out.println("ccc"); } static void test(int i) { System.out.println("iii"); } }
结果:
iii
多态其实就是约束了对象的使用场景;
方法的重载:方法名相同,参数列表不同(个数,顺序,类型);
public class Java05_Object { public static void main(String[] args) { AAA aaa1 = new AAA(); test(aaa1); BBB aaa2 = new BBB(); test(aaa2); AAA aaa3 = new BBB(); test(aaa3); } static void test(AAA aaa) { System.out.println("aaa"); } static void test(BBB bbb) { System.out.println("bbb"); } } class AAA { } class BBB extends AAA { }
结果:
aaa bbb aaa
-
面向对象 - 方法的重写
父类对象的方法其实主要体现通用性,无法在特殊的场合下使用,如果子类对象需要在特殊的场合下使用,那么就需要重写方法的逻辑,这个操作在Java中称为重写,这里的重写,并不意味着父类的方法被覆盖掉,只是在当前场合不使用,如果使用super关键字还是可以访问。
注意事项:
方法的重写要求子类的方法和父类的方法,方法名相同,返回值类型相同,参数列表要相同;
构造方法无法重写;
一个对象能使用什么方法,取决于引用变量的类型;
一个对象能使用什么属性,取决于引用变量的类型;
一个对象的方法具体的使用(直接或间接)是需要看具体的对象的;
一个对象的方法具体的使用是不需要看具体的对象的,属性在哪里声明在哪里使用;
public class Java06_Object { public static void main(String[] args) { Child06 child = new Child06(); child.test(); } } class Parent06 { String name = "zhangsan"; void test() { System.out.println("parent test..."); } } class Child06 extends Parent06 { String name = "lisi"; void test() { // System.out.println(this.name); // System.out.println(super.name); super.test(); System.out.println("child test..."); } }
结果:
parent test... child test...
-
面向对象 - 递归
所谓递归:方法调用自身,称之为递归方法;
递归方法应该有跳出的逻辑;
调用自身时,传递的参数需要有规律;
例:计算10以内的奇数之和
public class Java07_Object { public static void main(String[] args) { // TODO 面向对象 - 递归 // 所谓的递归:方法调用自身,称之为递归方法 int result = computeAP(10); System.out.println(result); } public static int computeAP(int num) { num = num % 2 == 0 ? num - 1 : num; if( num == 1 ) { //判断是否到临界点1 return 1; } else { return num + computeAP(num - 2); } } }
结果:
25
例:5的阶乘
public class Java07_Object { public static void main(String[] args) { // TODO 面向对象 - 递归 // 所谓的递归:方法调用自身,称之为递归方法 int result = computeAP(5); System.out.println(result); } static int computeAP(int num) { if( num <= 1 ) { return 1; } else { return num * computeAP(num - 1); } } }
结果:
120
-
面向对象 - 访问权限
public:公共的,访问权限修饰符;Java的源码,公共类只能有一个,而且必须和源码文件名相同。
main方法:main方法是由JVM调用的,JVM调用时应该可以任意调用,而不用考虑权限问题。
Java中的访问权限主要分为4种:
- private:私有的,同一个类中可以使用;
- (default): 默认权限,当不设定任何权限时,JVM会默认提供权限,包(路径)权限(子包也不能访问);
- protected:受保护的权限,子类(同不同包均可)可以访问
- public:公共的,任意使用;
类型 权限范围 private 同类 default 同类、同包(路径) protected 同类、同包(路径)、子类 public 公共 -
面向对象 - 外部类、内部类
Java中不允许外部类使用private、protected修饰;
所谓的外部类,就是在源码中直接声明的类;
所谓的内部类,就是在类中声明的类;
内部类就当成外部类的属性使用即可;
因为内部类可以看做外部类的属性,所以需要构建外部类对象才可以使用;
内部类的使用方式:
public class Java11_Object { public static void main(String[] args) { // TODO 面向对象 - 内部类 OuterClass outer = new OuterClass(); OuterClass.InnerClass innerClass = outer.new InnerClass(); } } class OuterClass { public class InnerClass { } }
JVM默认给类提供的构造方法,其实就是公共的,无参的构造方法;
private的两种使用情况:
- 类的创建过程复杂
- 类的对象消耗资源
-
面向对象 - final
Java中提供了一种语法,可以在数据初始化后不被修改,使用关键字final;
final可以修饰变量,变量的值一旦初始化后无法修改;
final可以修饰属性,那么JVM无法自动进行初始化,需要自己进行初始化,属性值不能发生变化;
一般将final修饰的变量称之为常量,或者不可变变量;
final可以修饰方法,这个方法不能被子类重写;
final可以修饰类,这个类不能再有子类;
final不可以修饰构造方法;
final可以修饰方法参数,一旦修饰,参数就无法修改。
public class Java12_Object { public static void main(String[] args) { // TODO 面向对象 final String name = "zhangsan"; //name = "wangwu"; //变量由final修饰,不能再修改,否则会报错 System.out.println(name); User12 user = new User12("wangwang"); //user.name = "wangwu"; //属性由final修饰,不能再修改,否则会报错 System.out.println(user.name); } } class User12 { public final String name; public User12(String name) { //使用构造方法进行初始化 this.name = name; } }
-
面向对象 - 抽象
抽象类:不完整的类,就是抽象类; abstract class 类名{};因为类不完整,所以无法直接构建对象。
抽象方法:只有声明,没有实现的方法; abstract 返回值类型 方法名(参数)
分析问题:对象(具体)=> 类(抽象)
编写代码:类(抽象)=> 对象(具体)
如果一个类中含有抽象方法,那么这个类是抽象类;
如果一个类是抽象类,它的方法不一定是抽象方法;
抽象类无法直接构建对象,但是可以通过子类间接构建对象;
如果抽象类中含有抽象方法,那么子类继承抽象类,需要重写抽象方法,将方法补充完整;
abstract不能和final同时使用,抽象类和抽象方法都不能使用final修饰。
public class Java13_Object { public static void main(String[] args) { // TODO 面向对象 - 抽象 //Person13 person = new Person13(); //抽象类不能直接构建对象,否则会报错。 Chinese13 c = new Chinese13(); //可以通过子类间接构建对象。 c.eat(); } } abstract class Person13 { //public abstract void eat(); public void test() { } } class Chinese13 extends Person13 { public void eat() { System.out.println("中国人使用筷子吃饭"); } }
-
面向对象 - 接口
所谓的接口,可以简单理解为规则;
基本语法:interface 接口名称 { 规则属性,规则行为 };
接口其实是抽象的;
规则的属性必须为固定值,而且不能修改;
属性和行为的访问权限必须为公共的;
属性应该是静态的;
行为应该是抽象的;
接口和类是两个层面的东西;
接口可以继承其它接口;
类的对象需要遵循接口,在Java中,这个遵循,称之为实现,类的实现接口,而且可以实现多个接口;
public class Java14_Object { public static void main(String[] args) { // TODO 面向对象 - 接口 Computer c = new Computer(); Light light = new Light(); c.usb1 = light; Light light1 = new Light(); c.usb2 = light1; c.powerSupply(); } } interface USBInterface { } interface USBSupply extends USBInterface { public void powerSupply(); } interface USBReceive extends USBInterface { public void powerReceive(); } class Computer implements USBSupply { public USBReceive usb1; public USBReceive usb2; public void powerSupply() { System.out.println("电脑提供能源"); usb1.powerReceive(); usb2.powerReceive(); } } class Light implements USBReceive { public void powerReceive() { System.out.println("电灯接收能源"); } }
结果:
电脑提供能源 电灯接收能源 电灯接收能源
-
面向对象 - 枚举
枚举是一个特殊的类,其中包含了一组特定的对象,这些对象不会发生改变;
枚举使用enum关键字使用;
枚举类会将对象放置在最前面,那么和后面的语法需要使用分好隔开;
枚举类不能创建对象,它的对象是在内部自行创建;
public class Java15_Object { public static void main(String[] args) { // TODO 面向对象 - 枚举 System.out.println(City.BEIJING.name); System.out.println(City.SHANGHAI.code); } } class MyCity { public String name; public int code; private MyCity(String name, int code) { this.code = code; this.name = name; } public static final MyCity BEIJING = new MyCity("北京", 1001); public static final MyCity SHANGHAI = new MyCity("上海", 1002); } //和下面写法大同小异 enum City { BEIJING("北京", 1001), SHANGHAI("上海", 1002); City(String name, int code) { this.name = name; this.code = code; } public String name; public int code; }
结果:
北京 1002
-
面向对象 - 匿名类
在模型场合下,类的名字不重要,我么指向使用类中的方法或功能,那么此时我们可以采用特殊的语法:匿名类;
所谓的匿名类,就是没有名字的类;
public class Java16_Object { public static void main(String[] args) { // TODO 面向对象 - 匿名类 Me me = new Me(); //me.sayHello(new Zhangsan()); //需要创建类,比较麻烦 me.sayHello(new Person16() { //无需创建类,实现一下抽象类传入姓名即可 @Override public String name() { return "Wangwu"; } }); new Bird16().fly(); new Fly() { public void fly() { System.out.println("使用飞行器飞翔"); } }.fly(); } } interface Fly { public void fly(); } class Bird16 implements Fly { public void fly() { System.out.println("使用翅膀飞翔"); } } abstract class Person16 { public abstract String name(); } class Me { public void sayHello(Person16 person16) { System.out.println("Hello " + person16.name()); } } class Zhangsan extends Person16 { public String name() { return "zhangsan"; } }
结果:
Hello Wangwu 使用翅膀飞翔 使用飞行器飞翔
-
面向对象 - Bean规范
Java中主要有两种类:
- 主要用于编写逻辑;
- 主要用于建立数据模型(Bean);
Bean类的设计规范:Bean规范
- 类要求必须含有无参、公共的构造方法;
- 属性必须私有化,然后提供公共的set、get方法;
public class Java17_Object { public static void main(String[] args) { // TODO 面向对象 - Bean规范 // 1.主要用于编写逻辑 // 2.主要用于建立数据模型 User17 user17 = new User17(); user17.setAccount("admin"); user17.setPassword("admin"); System.out.println(login(user17)); } public static boolean login(User17 user) { if (user.getAccount().equals("admin") && user.getPassword().equals("admin")) { return true; } else { return false; } } } class User17 { private String account; //私密信息使用private修饰 private String password; //私密信息使用private修饰 public void setAccount(String account) { //传入用户名 this.account = account; } public void setPassword(String password) { //传入密码 this.password = password; } public String getAccount() { //请求获得用户名 return account; } public String getPassword() { //请求获得密码 return password; } }
-
面向对象 - 作用域
如果属性和(局部)变量的名称相同,访问时如果不加修饰符,那么优先访问变量;
父子类有相同的属性时,优先体现子类属性;
当父类和子类中相同属性都是由static修饰时,与对象无关了,此时失去了继承的意义,子类不能再使用super调用父类属性;
public class Java18_Object { public static void main(String[] args) { // TODO 面向对象 - 作用域 User18 user = new User18(); user.test(); } } class Person18 { public static String name = "zhangsan"; //静态属性 } class User18 extends Person18 { public static String name = "lisi"; //静态属性 // public void test() { // //String name = "wangwu"; // System.out.println(name); // System.out.println(super.name); // } public static void test() { //静态方法 System.out.println(name); //System.out.println(super.name); //super会报错,super是个对象,在静态的方法中不能访问对象相关的内容 (先有类,再有对象,有类就可以使用静态的东西,但是能使用静态的东西不一定有对象) System.out.println(Person18.name); } }
结果:
lisi zhangsan