一面向对象的初步认知
1.什么是面向对象
2.面向对象与面向过程
以面向过程方式来进行处理,就关注洗衣服的过程,洗衣机是怎么来洗衣服,如何来甩干的等细节。以面向对象方式来进行处理,就不关注洗衣服的过程,只需要将衣服放进洗衣机,倒入洗衣粉,启动开关即可,通过对象之间的交互来完成的。
二、类定义和使用
上图左侧就是对洗衣机简单的描述,该过程称为对洗衣机对象(实体)进行抽象(对一个复杂事物的重新认知),但是这些简化的抽象结果计算机也不能识别,开发人员可以采用某种面相对象的编程言来进行描述,比如:Java语言。
1.简单认识类
2.类的定义格式
在java中定义类时需要用到class关键字,具体语法如下
// 创建类
class ClassName{
field; // 字段(属性) 或者 成员变量
method; // 行为 或者 成员方法
}
class WashMachine{public String brand; // 品牌public String type; // 型号public double weight; // 重量public double length; // 长public double width; // 宽public double height; // 高public String color; // 颜色public void washClothes(){ // 洗衣服System.out.println("洗衣功能");}public void dryClothes(){ // 脱水System.out.println("脱水功能");}public void setTime(){ // 定时System.out.println("定时功能");}}
3.类的实例化
3.1什么是实例化
在上一章中已经讲了new的作用(这里不详细讲了,本节重点讲构造方法)比如给上面洗衣机类实例化:
WashMachine a =new WashMachine(); 这个语句创建了一个名为a的自定义(这里为洗衣机类)类的类型,我们称为对象(java里面一切都是对象,比如数组类型,整型类型,浮点型类型等),实例化过程中会给他分配内存空间以及初始化(构造方法的作用)。实例化后就可以访问类里面的成员变量和成员方法了(即自定义类里面的变量和方法)
下面定义一个狗类并实例化
class PetDog {public String name;//名字public void barks() {System.out.println(name + ": 旺旺旺~~~");}public void wag() {System.out.println(name + ": 摇尾巴~~~");}}public class Test1{public static void main(String[] args) {PetDog dogh = new PetDog(); //通过new实例化dogh这个对象dogh.name = "阿黄";dogh.barks();dogh.wag();PetDog dogs = new PetDog();//实例化dogs这个对象dogs.name = "赛虎";dogs.barks();dogs.wag();}}输出结果:阿黄: 旺旺旺~~~阿黄: 摇尾巴~~~赛虎: 旺旺旺~~~赛虎: 摇尾巴~~~
4.类和对象的说明
三、this关键字
1.为什么要有this关键字
先看一个日期的类
//第1行public class Date {//2行public int year;//3行public int month;//4行public int day;public void setDay(int y, int m, int d){//5year = y;//6month = m;//7day = d;}public static void main(String[] args) {// 构造三个日期类型的对象 d1 d2Date d1 = new Date();Date d2 = new Date();// 对d1,d2的日期设置//9行 d1.setDay(2020,9,15);//10行 d2.setDay(2023,11,16);
public void setDay(int year, int month, int day){year = year;month = month;day = day;}
2.什么是this
//第1行public class Date {//2行public int year;//3行public int month;//4行public int day;public void setDay(int y, int m, int d){this.year = y; //当d1开始调用时,此代码看成d1.year=y;d2调用时看成d2.year=y;this.month = m; //..............................看成d1.month=m;.....................同上this.day = d; //....................同上................}public static void main(String[] args) {// 构造三个日期类型的对象 d1 d2Date d1 = new Date();Date d2 = new Date();// 对d1,d2的日期设置//9行 d1.setDay(2020,9,15);//10行 d2.setDay(2023,11,16);
public void setDay(int year, int month, int day){year = year; //如果不加this,编译器会认为这两个year都是局部变量(因为你传了一个year过来,将局部变量赋值给自己,编译器会报一个警告)month = month;day = day;}
3.this的特征
四、对象的构造及初始化
1.如何初始化对象
public static void main(String[] args) {int a;System.out.println(a);}// Error:(26, 28) java: 可能尚未初始化变量a
public class Date {public int year;public int month;public int day;public void setDay(int year, int month, int day){this.year = year;this.month = month;this.day = day;}public void printDate(){System.out.println(this.year + "/" + this.month + "/" + this.day);}}public static void main(String[] args) {Date d = new Date();d.printDate(); //因为new作用,默认初始化为0,结果为0/0/0d.setDate(2021,6,9); //给变量赋值d.printDate(); //赋值后结果为 2021/6/9}//屏幕结果//0/0/0
//2021/6/9
2.构造方法
2.1什么是构造方法
public class Date {public int year;public int month;public int day;// 构造方法:// 名字与类名相同,没有返回值类型,设置为void也不行// 一般情况下使用public修饰// 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次public Date(int year, int month, int day){this.year = year;this.month = month;this.day = day;System.out.println("Date(int,int,int)方法被调用了");}public void printDate(){System.out.println(year + "-" + month + "-" + day);}public static void main(String[] args) {// 此处创建了一个Date类型的对象,并没有显式调用构造方法Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了d.printDate(); // 2021-6-9}}
2.2什么时候调用构造方法
public class Date {public int year;public int month;public int day;// this(1900,1,1);必须是构造方法中第一条语句public Date(){//System.out.println(year);如果注释不取消掉,编译会失败this(1900, 1, 1);}// 带有三个参数的构造方法public Date(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}}
public Date(){this(1900,1,1);}public Date(int year, int month, int day) {this();}/*无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成闭环(递归调用)编译报错:Error:(19, 12) java: 递归构造器调用*/
3.初始化
3.1利用构造方法进行初始化
public class Date {public int year;public int month;public int day;public Date(int year, int month, int day){this.year = year;this.month = month;}public void printDate(){System.out.println(this.year + "-" +this.month + "-" +this.day);}public static void main(String[] args) {Date d = new Date(2021,6,9);d.printDate();}}// 屏幕输出方法2021-6-9。
3.2就地初始化
在声明成员变量时,就直接给出了初始值。就地初始化使所有对象的初始值一样,所以不推荐使用
public class Date {public int year = 1900;public int month = 1; //就地初始化在构造方法前面执行public int day = 1;public Date(){}public Date(int year, int month, int day) {}public static void main(String[] args) {Date d1 = new Date(2021,6,9);Date d2 = new Date();}}
五、封装
1.封装的概念
从语法上来说,就是被private修饰的成员变量或者成员方法,只能在当前类中使用。
2.访问限定符
访问权限除了可以限定类中成员的可见性,也可以控制类的可见性(自定义类不能私密和保护)如果把构造方法私密了,在类外便不能实例化对象了)
如果一个成员变量被private修饰,我们不能直接在类外访问,见以下代码
public class Computer {private String cpu;public Computer(String cpu) {this.cpu = cpu;}}public class TestComputer {public static void main(String[] args) {Computer p = new Computer("i7");System.out.println(p.cpu); // private属性:只能在Computer类中访问,这里编译器报错。}}
class MyClass {
// 私有变量
private int s;
// 构造函数
public MyClass(int value) { s = value;
}
// 普通公共方法
public void pin() {
// 在普通方法内部访问私有变量
System.out.println("私有变量的值是: " + s);
}
}
public class TestStudent { public static void main(String[] args) {
// 创建MyClass的实例
MyClass a = new MyClass(10);
// 调用MyClass实例的普通方法 a.pin();
}
}
//屏幕结果: 私有变量的值是: 10
封装方法分为get方法(读取私密变量的值)和set方法(设置或修改私密变量的值)
package Testdmol2;
public class U {
private int age=10;
public int getAge() { //封装方法
return age;
}public void setAge(int age) { //封装方法
this.age = age;
}
}
package Testdmo1;
import Testdmol2.U;public class J3_12two {
public static void main(String[] args) {
U u=new U();System.out.println(u.getAge());
}}
一个变量代表一个封装方法(因为封装方法(get方法)只能有一个返回值),我们可以通过下面的技巧快速写封装方法
我们在idea(建议使用Idea,不要用eclipse)中选中任意一行,点击鼠标右键,选中generate(生成),再点击getter和setter,再选中要修改的私密变量的值,就会自动生成以下代码
public int getAge() {
return age;
}public void setAge(int age) {
this.age = age;
}
总结:想访问私密变量,找公共方法即可,编译器提供了封装方法(只是公共方法的一种,变方便了,不需要自己写了。)
例题:尝试在不同包中访问一个默认类型的成员变量(使用封装方法)
package Testdmo1;
import Testdmol2.U;
public class J3_12two { public static void main(String[] args) {
U u=new U();
System.out.println(u.getAge());
}
}
package Testdmol2;
public class U {
int age=10;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}//输出结果为10
3.封装扩展之包
3.1包的概念
3.2导入包中的类
public class Test {public static void main(String[] args) {java.util.Date date = new java.util.Date();// 得到一个毫秒级别的时间戳System.out.println(date.getTime());}}
import java.util.Date;public class Test {public static void main(String[] args) {Date date = new Date();// 得到一个毫秒级别的时间戳System.out.println(date.getTime());}}
import java.util.*;public class Test {public static void main(String[] args) {Date date = new Date();// 得到一个毫秒级别的时间戳System.out.println(date.getTime());}}
import java.util.Date; import java.sql.Date; //编译器会报错
import java.util.*;import java.sql.*;public class Test {public static void main(String[] args) {Date date = new Date();// util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错java.util.Date date = new java.util.Date();//这样才正确。System.out.println(date.getTime());}}// 编译出错Error:(5, 9) java: 对Date的引用不明确java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配
3.3自定义包
3.4包的访问权限控制举例
package com.bit.demo1;public class Computer {private String cpu; // cpuprivate String memory; // 内存public String screen; // 屏幕String brand; // 品牌public Computer(String brand, String cpu, String memory, String screen) {this.brand = brand;this.cpu = cpu;this.memory = memory;this.screen = screen;}public void Boot(){System.out.println("开机~~~");}public void PowerOff(){System.out.println("关机~~~");}public void SurfInternet(){System.out.println("上网~~~");}
package com.bit.demo2;import com.bit.demo1.Computer;public class TestComputer {public static void main(String[] args) {Computer p = new Computer("HW", "i7", "8G", "13*14");System.out.println(p.screen);// System.out.println(p.cpu); // 报错:cup是私有的,不允许被其他类访问// System.out.println(p.brand); // 报错:brand是default,不允许被其他包中的类访问}} //关于这些修饰符后面有更详细的解释(继承里面)// 注意:如果去掉Computer类之前的public修饰符,代码也会编译失败(默认类型只能在同一个包访问)
六、static关键字
1.为什么要有static
1.对变量:如果想要使所有对象有相同的初始值,就要使用static.
例如三个对象s1、s2、s3,每个对象都有自己特有的名字、性别,年龄,学分绩点等成
员信息,这些信息就是对不同学生来进行描述的,但是如果他们班级一样,此时可以用static'
2.对方法:又例如想改变静态变量的值或给静态变量赋值可以用静态方法
3.对调用方式:你可以直接通过类名来调用静态成员方法与变量而不需要创建类的实例,变方便了。
2.static修饰成员变量
public class Student{public String name;public String gender;public int age;public double score;public static String classRoom = "Bit306";public static void main(String[] args) {// 静态成员变量可以直接通过类名访问System.out.println(Student.classRoom);// 也可以通过对象访问:但是classRoom是三个对象共享的,这种访问比较麻烦Student s1 = new Student("Li leilei", "男", 18, 3.8);System.out.println(s1.classRoom);}}
3.static修饰成员方法
共享访问:由于所有对象共享同一个静态成员方法的副本,因此任何一个对象对静态成员方法的修改都会影响到其他所有对象。这也是为什么静态成员方法通常用于执行不依赖于单个对象状态的操作。
我们在封装那里介绍了类外访问私密变量的方法,那在类外如何访问私密静态变量呢
//使用静态方法
class Student{
private static String classRoom = "Bit306";
public static String getClassRoom(){ //静态方法
return classRoom;
}
}
public class TestStudent { public static void main(String[] args) {
System.out.println(Student.getClassRoom());
}
}
//屏幕输出 Bit306
//使用普通方法:因为在普通成员方法里可以访问静态方法及静态变量(因为静态是对象共享的)
class MyClass {
// 静态私有变量
private static int s;
// 构造函数
public MyClass(int value) {
s = value;
}
// 普通方法
public void pin() {
// 在普通方法内部访问静态私有变量
System.out.println("静态私有变量的值是: " + s);
}
}
public class TestStudent {
public static void main(String[] args) {
// 创建MyClass的实例
MyClass a = new MyClass(10);
// 调用MyClass实例的普通方法
a.pin();
}
}
//输出: 静态私有变量的值是: 10
以上两种方法都要我们自己写,其实我们也可以使用静态的封装方法,与普通的封装方法一样,在选择变量时选静态的就可以了,见以下代码
package Testdmol1;import Testdmol2.U;
public class J3_12two {
public static void main(String[] args) {
U u=new U();
System.out.println(u.getClassRoom());
}
}
package Testdmol2;
public class U {int age=10;
private static String classRoom = "Bit306";
//下面红色代码为使用上面说的技巧后编译器自动生成的 选变量时选中classroom
public static String getClassRoom() {
return classRoom;
}
public static void setClassRoom(String classRoom) {
U.classRoom = classRoom;
}
//屏幕输出结果:Bit306
public static String getClassRoom(){System.out.println(this);return classRoom;}// 编译失败:Error:(35, 28) java: 无法从静态上下文中引用非静态 变量 thispublic static String getClassRoom(){age += 1;return classRoom;}// 编译失败:Error:(35, 9) java: 无法从静态上下文中引用非静态 变量 age
4. 静态方法中不能调用任何非静态方法,
public static String getClassRoom(){doClass();return classRoom;}// 编译报错:Error:(35, 9) java: 无法从静态上下文中引用非静态 方法 doClass(
4.static成员变量初始化
4.1就地初始化
就地初始化指的是:在定义时直接给出初始值
public class Student{private String name="huihuang";private int age=81;private static String classRoom = "计科3班";// ...}
4.2静态代码块初始化
那什么是代码块呢?继续往后看 ~~~
七、代码块
1.代码块概念以及分类
1.1普通代码块
普通代码块:定义在方法中的代码块public class Main{public static void main(String[] args) {{ //直接使用{}定义,普通方法块int x = 10 ;System.out.println("x1 = " +x);}int x = 100 ;System.out.println("x2 = " +x);}}// 执行结果x1 = 10x2 = 100
1.2 构造代码块
构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量(即非静态成员变量)。
public class Student{//实例成员变量private String name;private String gender;private int age;private double score;public Student() {System.out.println("I am Student init()!");}//实例代码块{this.name = "bit";this.age = 12;this.sex = "man";System.out.println("I am instance init()!");}public void show(){System.out.println("name: "+name+" age: "+age+" sex: "+sex);}}public class Main {public static void main(String[] args) {Student stu = new Student();stu.show();}}// 运行结果I am instance init()!I am Student ()!name: bit age: 12 sex: man
1.3 静态代码块
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。
public class Student{private String name;private String gender;private int age;private double score;private static String classRoom;//实例代码块{this.name = "bit";this.age = 12;this.gender = "man";System.out.println("I am instance init()!");}// 静态代码块static {classRoom = "bit306";System.out.println("I am static init()!");}public Student(){System.out.println("I am Student init()!");}public static void main(String[] args) {Student s1 = new Student();Student s2 = new Student();}}/*运行结果I am static init()!
I am instance init()!
I am Student init()!
I am instance init()! //发现这里静态内容没打印
I am Student init()!*/
八、对象的打印
如果直接给对象名打印,结果是一个引用(地址)
public class Person {
String name;
String gender;
int age;
public Person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public static void main(String[] args) {
Person person = new Person("Jim", "男", 18);
System.out.println(person);
}
}
//输出结果 Person@4554617c
上面也介绍了打印对象的方法,我们回忆一下一开始的狗类
class PetDog {public String name;//名字public String color;//颜色// 狗的属性public void barks() {System.out.println(name + ": 旺旺旺~~~");}// 狗的行为public void wag() {System.out.println(name + ": 摇尾巴~~~"); //在类里面直接写name即可打印值} //在类外面写对象名.name即可打印值}public class Test1{public static void main(String[] args) {PetDog dogh = new PetDog(); //通过new实例化dogh这个对象dogh.name = "阿黄";dogh.barks();dogh.wag();PetDog dogs = new PetDog();//实例化dogs这个对象dogs.name = "赛虎";dogs.barks();dogs.wag();}}输出结果:阿黄: 旺旺旺~~~阿黄: 摇尾巴~~~赛虎: 旺旺旺~~~赛虎: 摇尾巴~~~以上方法太过复杂,下面介绍一个简单的方法。
blic class Person {String name;String gender;int age;public Person(String name, String gender, int age) {this.name = name;this.gender = gender;this.age = age;}public String toString() {return "[" + name + "," + gender + "," + age + "]";}public static void main(String[] args) {Person person = new Person("Jim","男", 18);System.out.println(person);}}// 输出结果:[Jim,男,18]