类和对象
面向对象的初步认识
什么是面向对象
java是一门纯面向对象的语言,简称(OOP)在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序设计,拓展以及维护都非常友好。
面向对象与面向对象过程
1.传统洗衣服
注重洗衣服的过程,不同衣服洗的方式不一样,晾干时间不一样。
2.现代洗衣服
总共有四个对象:人,衣服,洗衣机,洗衣粉。
类的定义和使用
面向对象程序设计关注的是对象,而对象是现实生活中的实体,比如:洗衣机。但洗衣机,计算机并不认识,需要开发人员告诉计算机什么是洗衣机。
上图就是对洗衣机的简单概述,该过程称为对洗衣机对象(实体)进行抽象(对一个事物的重新认识),但这些简化的抽象结果计算机也不能识别,开发人员可以采用某种面向对象的编程语言来进行描述。
简单认识类
类是用来对一个实体(对象)来进行描述,主要描述该实体(对象)具体有哪些属性(外观尺寸),哪些功能(用来干啥),描述完成后计算机就可以识别了。
比如:洗衣机,他是一个品牌,在Java中可以看成一个类别。
属性:产品品牌,型号,产品重量,外观尺寸。
功能:洗衣,烘干,定时…
类的定义格式
在Java中定义类时需要用到class关键字
//创建类
class ClassName{
filed; //字段(属性)或者,成员变量
method;//行为或者成员方法
}
class为定义类的关键字,ClassName为类的名字,{}为类的主体
class WashMachine{
public String brand;//小天鹅
public String trpe;//型号
//字段 属性
}
public class washClothes(){//洗衣服
System.out.println("洗衣功能");
}
public class dryClothes(){//脱水
System.out.println("脱水功能");
}
public class settime(){//定时
System.out.println("定时功能");
}
注意事项:
- 类名注意采用大驼峰定义。
- 成员前写法统一为public
- 不带关键字static
类的实列化
定义一个类,就相当于在计算机中定义一个新的类型,与int double类似,只不过int与double是Java语言自带的内置类型。而类是用户自定义了一个新类型。
用类类型创建对象的过程,称为类的实例化。
public class Test2{
public static void main(String[] args){
WashMachine washMachine1=new WashMachine();
washMachine1.brand="小天鹅";
System.out.println(washMachine1.brand);
WashMachine washMachine2=new WashMachine();
washMachine2.brand="一个品牌·";
System.out.println(washMachine2.brand);
public class test2{
public static void main)String[] args){
Person person1 =new Person();
person1.name="zhangsan";
person.eat();
System.out.println();
}
注意事项:
- new关键字用于创建一个对象的实例。
- 使用.来访问对象中的属性和方法。
- 同一个类可以创建多个实例。
类和对象的说明
1.类只是一个模型,用来对一个实体进行描述,限定了类有哪些成员。
2.类是一种自定义的类型,可以用来定义变量。
3.一个类可以实例化出多个对象,实例化的对象占用实际的物理空间,储存类成员变量。
this引用
public class TestDate{
public int year;
public int month;
public int day;
public void setDate(int y,int m,int d){
year=y;
month=m;
day=d;
}
public void printDate(){
System.out.println("年: "+year+"月:"+month+"日:"+day)'
}
public static void main(String[] args){
TestDate testDate1=new TestDate();
TestDate testDate2=new TestDate();
TestDate testDate3=new TestDate();
testDate1.setDate(y:1998,m:1,d:9);
testDate1.printDate();
}
以上代码定义一个日期类,然后main方法中创建三个对象,并通过Date类中的成员方法对对象进行设置和打印,代码整体逻辑非常简单,没有任何问题。
1.形参名不小心与成员变量名相同:
public void setDay(int year,int month,int day){
year=year;
month=month;
day=day;
}
2.三个对象都在调用setDate和printDate函数,但是这两个函数中没有任何关系对象的说明,setDate和printDate函数如何知道打印的是哪个对象。
什么是this引用
this引用指向当前对象(成员方法运行时调用成员函数方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作是透明的。
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.year);
}
}
注意:this引用的是调用函数成员的方法。
this引用的特性
1.this的类型:对应类型引用,即哪个对象调用就是哪个对象的引用类型
2.this只能是在成员方法中使用
3.在成员方法中this只能引用当前对象,不能再引用其他变量。
4.this是成员方法的第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责接受。
对象的构造及初始化
如何初始化对象
在Java方法内部定义一个局部变量,必须要初始化,否则会编译失败。
public static void main(String[] args){
int a;
System.out.println(a);
}
要让上诉代码通过编译,非常简单,只需要正式使用a之前,给a设置一个初始值即可。如果是对象
public static void main(String[] args){
Date d=new Date();
d.printDate();
d.setDate(2021,6,9);
d.printDate();
}
每次对象创建好后调用SetDate方法才可以将具体的日期设置
局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?
构造方法
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期只调用一次。
构造方法: 方法名(参数列表)(方法体)没有返回值的方法,并且方法名必须与类名保持一致。
public TestDate(){
System.out.println("没有参数的构造方法");
}
public TestDate(int year,int month,int day){
this.month=month;
this.year=year;
this.day=day;
System.out.println("有3个参数的构造方法");
}
public static void main(String[] args){
//此处创建了一个Date类型的对象,并没有显示调用的构造方法
Date d=new Date(2021,6,9);//输出Date(int,int,int)方法被调用了
d.printDate();//2021-6-9
}
特性
1.名字必须与类名相同
2.没有返回值类型,设置为void也不行。
3.创建对象时由编译器自动调用,并且在对象的生命周期只调用一次
4.构造方法可以重载(用户根据自己需求提供不同参数的构造方法)
public class Date{
public int year;
pulic int month;
public int day;
//无参构造函数
public Date(){
this.year=1900;
this.month=1;
this.day=1;
}//带有三个参数的构造方法
public void printDate(int year,int month,int day){
this.year=year;
this/month=month
this.day=day;
}
5.如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
public class Date{
public int year;
public int month;
public int day;
}
public void printDate(){
System.out.println(year+"-"+month+"-"+day);
}
public static void main(String[] args){
Date d=new Date();
d.printDate();
}
}
上述Date类中,没有定义任何构造方法,编译器会默认生成一个不带参数的构造方法。
注意:一旦用户定义,编译器则不在生成。
6,构造方法中,可以通过this调用其他构造方法来简化代码。
调用构造函数方法this()
但是要注意:
1.这个写法只能在构造方法中才这样写
2.构造方法当中,不能调用自己
3.只能放在构造方法的第一行
public class Date{
public int year;
public int month;
public int day;
//无参构造方法--内部给各个成员赋值的初始值,该部分功能与三个参数的构造方法重复
//此处可以在无参构造方法中通过this调用三个参数的构造方法。
this(…)必须是构造方法中第一条语句。
不能形成环
public Date(){
this(1900,1,1);
}
public Date(int year,int month,int day){
this();
}
默认初始化
成员变量在没有初始化的时候,都有一个默认值。引用类型的值:都是null。
int 0
float o.of
char ‘\u0000’
boolean false
public class Test{
public static void main(String[] args){
Student student =new Student();
student.print();
Student student2 =null;//student2 不指向任何对象
public class Date{
public int year;
public int month;
public int day;
public Date(int year,int month,int day){
System.out.println(this.year);
System.out.println(this.month);
System.out.println(this.day);
}
public static void main(String[] args){
//此处a没有初始化,编译报错
//Error:(24,28)java:可能尚未初始化变量a
//int a;
//System.out.println(a);
Date d=new Date(2021,6,9);
}
}
要搞清楚这个过程,就需要知道new关键字背后所发生的一些事情:
Date d =new Date(2021,6,9);
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
1.检测对象对应的类是否加载,如果没有加载则加载
2.为对象分配内存空间
3.处理并发安全问题
比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突。
4.初始化分配空间
即:对象空间被申请好之后,对象包含的成员已经设置好了初始化。
就地初始化
在声明成员变量时,就直接给出了初始值。
封装
封装的概念
面向对象程序的三个特性:封装,继承,多态。而类和对象阶段,主要研究的就是封装特性。
需求:我想隐藏我的实现内容。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
访问限定符
java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据方法结合在一起,更符合人类事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。
NO | 范围· | private | default | protected | public |
---|---|---|---|---|---|
1 | 同一包中的同一类 | √ | √ | √ | √ |
2 | 同一包中的不同类 | √ | √ | √ | |
3 | 不同包中的子类 | √ | √ | ||
4 | 不同包中的非子类 | √ |
比如:
public:可以理解为一个人的外貌特征,谁都可以看得到。
default:对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私。
private:只有自己知道,其他人都不知道。
【说明】
- protected主要是用在继承中,继承部分详细介绍。
- default权限指:什么都不写的默认权限
- 访问权限除了可以限定类中成员的可见性,也可以控制类的可见性。
public class Computer{
private String cpu;
private String memory;
public String screen;
String brand;
public Computer(String brand,String cpu,String memory,String screnn){
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 Surflnternet(){
System.out.println("上网---");
}
public class TestComputer{
public static void main(String[] args){
Computer p =new Computer("HW","i7","8G","13*14");
System.out.println(p.head);
封装扩展之包
包的概念
在面对对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。
在Java中也引入了包,包是对类,接口等的封装机制的体现,是一种对类或者接口等的接口等的很好的组织方式,比如:一个包中的类不想被其他被其他包中不想被其他包中的类使用。包还有一个重要作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
导入包中的类
java中以提供了很多现成的类供我们使用,列如Date:可以使用java.util.Date导入iava.util这个包中的Date类
public class Test{
public static void main(String[] args){
java.util.Date date=new java.util.Date();
//得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
但是这种写法比较麻烦一些,可以使用import语句导入包。
import java.util.Date;
public class Test{
public static void main(String[] args){
Date date= new Date();
//得到一个毫秒级别的时间戳
System.out.println(date.getTIme());
}
}
如果需要使用java.util中的其他类,可使用import java.util*
在这种情况下需要使用完整的类名
import java.util.*;
import java.sql.*;
public class Test{
public static void main(String[] args){
java.util.Date date=new java.util.Date();
System.out.println(date.getTime());
}
}
可以使用import static导入包中静态的方法和字段
import static java.lang.Math.*;
public class Test{
public static void main(String[] args){
double x=30;
double y=40;
//静态导入的方式写起来更方式
//double result=Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
double result=sqrt(pow(x,2)+pow(y,2));
System.out.println(result);
}
}
注意事项:import和C++的#include差别很大,C++必须#include来引入其他文件内容,但是Java不需要。import只是为了写代码的时候更方便。import更类似于C++的namespace和using。
自定义包
基本规则
- 在文件的最下方加上一个package语句指定改代码在哪个包中。
- 包名需要尽量指定成唯一的名字。
- 包名要和代码路径相匹配。例如创建com.bit.demo1的包,那么会存在一个对应的路径来储存。
- 如果一个类没有package语句,则该类被放到一个默认包中。
操作步骤
1.在IDEA中先新建一个包:右键src->新建->包
public class Tectcom{
public static void main(String[] args){
TestBit testBit =new TestBit();
Test test =new Test ();
}
}
2.在弹出的对话框输入包名,例如com.bit.demo1
3.在包中创建类,右键包名->新建->类,然后输入类名即可。
4.此时可以看出我们的磁盘上的目录结构已经被IDEA自动创建出来了。
5.同时我们也看到了,在新创建的Test.java文件的最上方,就出现了一个package语句。
包的访问权限控制举例
Computer类位于com.bit.demo1包中,TestComputer位置com.bit.demo2包中:
package com.bit.demo1;
public class Computer{
private String cpu;
private 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;
}
package com.bit.demo2;
import com.bite.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);//报错:cpu是私有的,不允许被其他类访问
//System.out.println(p.brand);//报错:brand是default,不允许被其他包中的类访问。
}
}
常见的包
1.java.lang:系统常用基础类
2.java.lang.reflect:java 反射编程包;
3.java.net:进行网络编程开发包。
4.java.util:是java提供的工具程序包。
Static成员
对成员进行实例化
public string name;
public int age;
public string classRoom;//static[教室只有一份]
Student student1 =new Studet("zhngsan","18","301");
Student student1 =new Studet("lisi","6","301");
Student student1 =new Studet("wangwu","28","301");
可以比较,教室都是一致的,假设三个同学是同一个班的,那么他们上课肯定是在同一个教室,那既然在同一个教室,那能否给类中再加一个或=成员变量,来保存同学上课时的教室。答案是否定的。
之前,在Student类中定义的成员变量,每个对象都会包含一份(称之为实例变量),因为需要使用这些信息来描述具体的学生。而现在要表示学生来上课的教室,这个教室属性并不需要每个学生对象中都储存一份,而是需要让所有的学生来共享。在JAVA中,被static修饰的成员,成之为静态变量,也可称之为类成员,其并不属于某个具体的对象。
static修饰成员变量
static修饰成员变量,称为静态变量,静态变量最大特性:不属于某个具体的变量,是所有对象共享的。
【静态成员变量特性】
1.不属于某个具体的对象,是类的属性,所有对象共享,不储存在某个对象空间中
2.既可以通过对象访问空间,也可以通过类名访问,但一般更推荐使用类名访问
3.类变量储存在方法中
4.生命周期伴随类的一生
静态成员的访问方式:不建议通过对象的引用访问。
建议通过类名的方式进行访问。
System.out.println("教室是:"+student1.classRoom);//不建议
System.out.println("教室是:"+Student.classRoom);
引用可以指向引用吗?不可以
Student student1 =new Student:("zhangsan","18");
Student student2 =student1;
引用只能指向对象:上述代码的意思是:student2这个引用指向了student1这个引用所指向的对象。
2.一个引用,能不能指向多个对象?
不可以
3.Person p =null;代表不指向任何对象。
static修饰成员方法
一般类中的数据成员都设置为private,而成员方法设置为public,那设置之后,Student类中classRoom属性相同在类外访问?
public class Student{
private String name;
private String gender;
}
public class TestStudent{
public static void main(String[] args){
System.out.println(Student.classRoom);
}
}
//编译失败
Error:(10,35)java:classRoom在extend01.Student中是控制private访问控制
那static属性应该如何访问?
java中,被static修饰的成员变量方法称为静态成员变量,是类的方法,不是某个对象所特有的。静态成员一般由静态方法访问的。
【静态方法特性】
1.不属于某个特定的对象,是类方法。
2.可以通过对象调用,也可以通过类名。静态方法名()方式调用。
3.不能在静态方法中访问任何非静态成员变量。静态方法 不依赖对象
public static String getClassRoom(){
Sytem.out.println(this);
return classRoom;
}
//编译失败:Error:(35,28)java:无法从静态上下文中引用非静态变量:this
public static String getClassRoom(){
age+=1;
return classRom;
}
//编译失败:Error:(35,9)java:无法从静态上下文中引用非静态变量age
4.静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递。
public static String getClassRoom(){
doClass();
return classRoom;
}
//编译报错:Error`:(35,9)java:无法从静态上下文中引用静态方法doClass()`
静态修饰成员的初始化
注意:静态初始化变量一般不会放在构造方法中来初始化,构造方法的是与对象相关的实例属性
静态成员变量的初始化分为两种:就地初始化和静态代码初始化
1.就地初始化:在定义时直接给出初始值
public class Student{
private String name;
private String gender;
private int age;
}
2.静态代码初始化:什么是代码块呢?
代码块
代码块概念即分类
使用{}定义的一段代码称为代码块。
- 普通代码块
- 构造块
- 静态块
- 同步代码块
普通代码块
普通代码块:定义在方法中的代码块
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=10
x2=100
构造代码块
定义类的代码块。也叫:实例代码块,构造代码块一般用于初始化实例成员变量。
public class Student{
//实例成员变量
private String name;
private STring gender;
}
public void main(String[] args)
{
System.out.println(name);
}