课程目录
- 面向对象的基本概念
- 类和对象
- 类和对象的定义格式
- 对象与内存分析
- 封装性
- 构造方法
- this关键字
- 值传递与引用传递
- 对象的一对一关系
- static关键字
- main方法分析
- 代码块
- 单例设计模式
- 对象数组与管理
1.面向对象基本概念
面向对象思维方式:先整体后集体先抽象后具体。
如何学习面向对象:
1.掌握一门面向对象语言的语法
2.熟悉面向对象的设计原则
3.熟悉慢性单纯的设计模式
2.类与对象
什么是类?
1.类是:分类 类别
2.通过分类,我们可以区别不同的事物种类,在日常生活中,我们常常这样做
3.所以,类是一组具有相同特性(属性)与行为(方法)的事物集合
类与对象的关系
1.类表示一个共性的产物,是一个综合的特征,而对象,是一个个个性的产物,是一个个个体的特征。
2.类由属性和方法组成
属性:就相当于一个个的特征
方法:就相当于人的一个个行为,例如:唱,跳,rap,蓝球
3.类和对象的定义格式
定义一个类:
class类名称{
属性名称;
返回值类型 方法名称(){}
}
对象的定义:
一个类要想真正的进行操作,则必须依靠对象,对象的定义格式如下:
类名称 对象名称=new 类名称();
在Java中,对象声明有两种含义
声明对象:Horse horse=null;
表示声明了一个对象,但是此对象无法使用,horse没有具体的内存指向
实例化对象:horse=new Horse();
//表示实例化了对象,可以使用
按照以上方式就能产生对象了
如果要想访问类中的属性或者方法(方法的定义),
可以依靠以下的语法形式:
访问类中的属性:
对象 . 属性;
调用类中的方法:
对象 . 方法();
通过对象调用方法:
horse.eat();
匿名对象调用方法
new Horse().eat();
package test;
public class test{
public static void main(String[] args){
Horse h=null;//声明一个变量(除了八种基本数据类型外,都是引用数据类型,包括数组)
//创建一个Horse类型的对象,实例对象
h=new Horse();
//有了对象,我们就可以调用对象的属性和方法
h.name="赤兔马";
h.age=30;
h.run();//调用方法,那么方法就会被执行。
h.eat();
//匿名对象,只能使用一次,用完后,该对象就会被释放
new Horse().eat();
h=null;//把对象释放
//h.eat();//当对象不存在时,调用该对象的属性和方法将报错(空指针)
}
}
//自定义一个类(类型)
class Horse{
//在类中定义属性
String name;
int age;
public void run(){
System.out.println("马跑步"+name);
}
public void eat(){
System.out.println("我吃草");
}
}
4.对象内存分析
1.new关键字表示创建一个对象
2.new关键字表示实例化一个对象
3.new关键字表示申请 内存空间
注意:如果使用一个没有申请内存空间的对象,会报空指针异常
java.lang.NullPointerException
栈内存存放类型名,存放基本数据类型
堆内存存储对象用的
1.在栈内存中存个变量名
2.语句二表示在堆内存中new一块区域用来存放属性和方法,并把地址存在栈内存中
注意,此时“小白”仅仅是地址,2这样写是为了方便看。
声明两个对象,一个实例化一个没有实例化
对象之间的赋值
注意:如果我更改了horse1.name,那么horse2.name也会改变,同理也是这样。因为他俩指向同一个内容
注意:当horse2=horse1;后对horse2.name改,horse1.name也会改,因为指向的地址相同。
类与对象小结
- new关键字:表示向内存申请空间,也表示实例化一个对象,创建一个对象。
- 一个对象在内存中的大小,由该对象的所有属性所占的内存大小的总和,引用类型变量在32位系统上占4个字节,在64位系统上占8个字节加上额外的对象隐形数据所占的大小。(String字符串是引用类型变量,不是基本数据类型变量)
- 相同的类型才可以赋值
- 不同的引用,指向同一个对象,任何一个引用改变对象的值,其他引用都会反映过来
- 当一个堆中的对象没有被任何引用变量所指向时,该对象会被JVM的GC程序认为是辣鸡对象,从而被回收。
- 编程时要注意的问题:在确定不使用对象时,要尽早释放对象:引用=null//匿名对象,只能使用一次,用完后,该对象就会被释放如:
new Horse().eat(); h=null;//把对象释放
5.封装性
封装性的概念
1.封装性是面向对象思想的三大特征之一。
2.封装就是隐藏实现细节,仅对外提供访问接口
封装有:类的封装,属性的封装,方法的封装,组件的封装,模块化封装,系统级封装…
封装的好处
1.模块化
2.信息隐藏
3.代码重用
4.插件化易于调试
5.具有安全性
封装的缺点会影响执行效率
package test;
public class test{
public static void main(String[] args){
//未封装之前,可以直接调用
Person p1=new Person();
p1.name="feifei";
p1.age=18;
}
}
/*封装性*/
//没有封装之前
class Person{
//属性的封装
String name;
int age;
}
如果属性没有封装,那么在本类之外创建对象后,可以直接访问属性
private关键字:访问权限修饰符,public表示共有的,private表示私有的。私有的属性或者方法,只能在本类中访问,共有的属性或者方法,可以被类外的其他类访问。想要早类外部访问私有属性,我们需要提供共有的方法来间接访问
通常在一个类中,属性都私有化,并对外体提供getter and setter 方法
封装后
class Person{
//加上private,封装属性
private String name;
private int age;
}
//未封装之前,可以直接调用
Person p1=new Person();
p1.name=“feifei”;
p1.age=18;
想要类外部访问私有属性,我们需要提供共有的方法来间接访问
//封装之后调用
Person p1=new Person();
p1.setName(“feifei”);
p1.setAge(18);
package test;
public class test{
public static void main(String[] args){
//封装之后调用
Person p1=new Person();
p1.setName("feifei");
p1.setAge(18);
}
}
/*封装性*/
//没有封装之前
class Person{
//属性的封装
private String name;
private int age;
//getter and setter
//对外提供一个为name属性设值方法
public void setName(String name){
this.name=name;//等号后面的name为括号内参数name,this后name为class的属性name
}
//对外提供一个获取name属性的方法
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
6.构造方法
什么是构造方法
构造方法的定义
构造方法是在类中定义的,构造方法的定义格式:方法名称与类名称相同,无返回值类型的声明:
public Dog();{}
对象的实例化语法:
Dog dog=new Dog(); //Dog后面有个括号,带括号表示调用了方法,此时调用的方法就是构造方法了
1.构造方法就是类构造对象的时候调用的方法,用于对象的初始化工作
2.构造方法是实例化一个类的对象时,也就是new的时候,无需像普通方法对象名.方法名。最先调用的方法。
3.新手在刚开始很容易将class定义到main函数中*。造成Java出现No enclosing instance of type E is accessible. Must qualify the allocation with an enclosing
构造方法的调用:
Dog dog =new Dog();
//new的过程中默认调用了dog()构造方法;
Dog dog1=new Dog(“旺旺”,18);
package test;
import java.util.Arrays;
import java.util.Random;
public class test2 {
public static void main(String[] args) {
Dog dog =new Dog();
//new的过程中默认调用了dog()构造方法;
Dog dog1=new Dog("旺旺",18);
}
}
//构造方法是在类中定义的;/
class Dog {
// 方法名称与类名称相同
// 注意:无返回值类型的声明,不要写void
//无参构造方法为默认,可以不写,前提是后面还有构造方法
public Dog() {
System.out.println("构造方法已经调用了");
}
//重载构造方法,无返回值类型声明,不写void
public Dog(String name,int age){
this.name=name;
this.age=age;
System.out.println("带两个参数的构造方法执行了");
}
private String name;
private int age;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
构造方法的重载
无参构造方法:
public Dog(){}
带一个参数的构造方法:
public Dog(String name){
this .name=name;
}
带多个参数的构造方法:
public Dog(String name,int age){
this .name=name;
this.age=age;
}
构造方法A如何调用构造方法B
this(方法B名字);
构造方法小结
7.this关键字
在Java基础中,this关键字是一个非常重要的概念。使用this关键字可以完成以下操作:
- 调用类中的属性
- 调用类中的方法或构造方法
- 表示当前对象
调用类中的属性
谁调用我,谁就是当前对象。谁就是this,代码中是cat
调用类中的方法或构造方法
补充:this前面可以加上类名.this。在后面的内部类知识中可能会涉及到。
8.值传递和引用传递
知识回顾:成员变量与局部变量的区别
示例一:值传递
package test;
public class test2 {
public static void main(String[] args) {
int x = 10;
method(x);
System.out.println("x=" + x);
}
public static void method(int mx) {
mx = 20;
}
}
运行结果X=10;为啥不是20呢
因为x和mx 都是在方法中定义的,都存储在栈内存中,只是mx被赋值成了20。 Java都是值传递。X并没有变化
示例二:引用传递
package test;
public class test2 {
public static void main(String[] args) {
Duck d=new Duck();
menthod(d);
System.out.println("鸭子的年龄是"+d.age);;
}
public static void menthod(Duck duck){
duck.age=5;
}
}
class Duck{
int age=2;//省略封装
}
运行结果:鸭子的年龄是5,注意,new操作后,栈内存存的是d的地址、且class Duck后存的是成员变量,放在对内存中
当变量存的是地址的时候,操作就是引用传递。
当变量存的是值的时候,操作就是值传递。
示例三:String类型传递
package test;
//字符串本身就是一个对象
public class test2 {
public static void main(String[] args) {
String name ="小飞";
method(name);
System.out.println("名字是"+name);
}
public static void method(String sname){
sname="小贝";
}
}
String的值储存在堆内存当中,一个字符串相当于new一个对象出来。字符串本身就是一个对象
在String 中有两个对象出现。”“小飞”和“小贝”
示例四:还是String传递
package test;
public class test2 {
public static void main(String[] args) {
Person p=new Person();
menthon(p);
System.out.println("人名是"+p.name);
}
public static void menthon(Person per ){
per.name="贝贝";
}
}
class Person{
String name ="飞飞";//省略封装
}
输出结果:人名是贝贝
注意:String是引用型数据变量,String name 表示在堆内存中开辟一块内存存储的是name的地址。=“飞飞”表示在这块地址上命名
除了基本数据类型在栈内存完成之外,其余的都在堆内存完成。
自己画图画几遍
9.对象的一一对应关系
两个对象之间一一对应关系:
比如:
一个英雄(hero)对一个兵器(weapon)代码如何表示?
补充说明
要注意Weapon weapon和 Weapon wepon = new Weapon() 的区别
前面讲的是声明一个变量,变量名为weapon,变量类型为Weapon 后面讲的是创建一个Weapon 对象,并把它赋给了变量wepon。也就是说wepon 实际上引用了一个Weapon 类型的对象
其实类名不是作为数据类型,只能说将这个类的对象作为返回值。意思就是说,这个方法的返回值不是普通的数据类型,而是一个类对象。这样做可以避免一个方法要返回N多的数据,比如说,你要同一个方法中得到name和age,但是java又不能返回多个值,除了可以使用一个字符串或者字符串数组存放外,我们可以定义一个Student对象,对象中包含name和age属性,这样就可以用这个对象把属性封装起来以及方法,一起返回。
1.在hero类定义一个Weapon类型的weapon ,(在本类中定义一个对方方法)
2.设置weapon的getter and setter方法,单项一对一,若双向可在weapon类同样设置
3.关联起来
//双向一对一,英雄得到他的兵器,反过来兵器也能得到他的英雄
//单向一对一,英雄捡到兵器,兵器不知道英雄
package test;
public class test{
public static void main(String[] args){
Hero hero =new Hero("刘备",18);
Weapon weapon=new Weapon("剑",3);
//把两个对象关联起来
hero.setWeapon(weapon);
weapon.setHero(hero);
String name=hero.getName();
int age=hero.getAge();
Weapon w=hero.getWeapon();
System.out.println("我是"+name+",我"+age+"岁,武器是"+w.getName()+",等级是"+w.getGrade());
}
百度谷歌了一下相关资料。原来我写的内部类是动态的,
也就是开头以public class开头。
而主程序是public static class main。
在Java中,类中的静态方法不能直接调用动态方法。
只有将某个内部类修饰为静态类,然后才能够在静态类中调用该类的成员变量与成员方法。
所以在不做其他变动的情况下,
最简单的解决办法是将public class改为public static class.
//通过英雄来获取它的信息
//英雄类
public static class Hero{
private String name;
private int age;
private Weapon weapon;//在本类中定义一个其他类类型的私有变量
//一对一对应关系
//设置getter and setter方法
public void setWeapon(Weapon weapon){
this.weapon=weapon;
}
public Weapon getWeapon(){
return weapon;
}
public Hero(){}
public Hero(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
//武器类
public static class Weapon{
private String name;
private int grade;
private Hero hero;//设置Hero类型的hero;
//设置getter and setter 方法
public void setHero(Hero hero){
this.hero=hero;
}
public Hero getHero(){
return hero;
}
public Weapon(){}
public Weapon(String name,int grade){
this.name=name;
this.grade=grade;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setGrade(int grade){
this.grade =grade;
}
public int getGrade(){
return grade;
}
}
}
10.static关键字
static关键词的作用:
1.使用static关键词修饰一个属性
声明位static的变量实质上是全局变量(生命周期变长了,从程序启动到程序结束)
2.使用static关键字修饰一个方法
通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法
3.使用static关键字修饰一个类(普通类不能用static,只有内部类才能用static)
static关键字总结
1.静态对象或方法不属于对象,依赖类。
2.静态变量是全局变量,生命周期从类被加载后一直到程序结束
3.静态变量只有存一份,在静态方法区存储
4.静态变量是本类所有对象共享一份
5.建议不要使用对象名去调用静态数据,直接使用类名调用
6.static修饰一个方法,那么该方法属于类,不属于对象,直接用类名调用。意味着没有创建对象也能用
7.静态方法不能访问非静态的数据,只能访问静态。this和super都无法出现在static 修饰的方法中
package test;
public class test{
public static void main(String[] args){
//Role beibei=new Role("刘备","蜀国");
//Role yuanchuang =new Role("云长","蜀国");
//Role feifei =new Role("张飞","蜀国");
Role beibei=new Role("刘备");
Role yuanchuang =new Role("云长");
Role feifei =new Role("张飞");
System.out.println(beibei.getInfo());
System.out.println(yuanchuang.getInfo());
System.out.println(feifei.getInfo());
System.out.println("-------静态变量是本类所有对象共享一份-------");
beibei.country="晋朝";
System.out.println(beibei.country);
System.out.println(yuanchuang.country);
System.out.println(feifei.country);
System.out.println("-------建议不要使用对象名去调用静态数据,直接使用类名调用-------");
beibei.country="汉朝";
System.out.println(Role.country);//因为country是静态属性,所以可以用类名点属性
System.out.println(Role.country);
System.out.println(Role.country);}
}
//角色
class Role{
private String name;
//private String country;不想写三个蜀国所以:
static String country="蜀国";//静态变量(全局变量)
public Role(String name,String country){
this.name=name;
this.country=country;
}
//去掉country,可行
public Role(String name){
this.name=name;
}
public void setName(String name){
this.name =name;
}
public String getName(){
return name;
}
//静态方法不能访问非静态的数据
public static void setCountry(String country){
//this.country=country;
//Cannot use this in a static context
//意思是:this关键字不能在static静态方法中使用,具体解释看下文
Role.country=country;
}
public String getInfo(){
return "名字:"+name+",国家:"+country;
}
}
方法加了static,就会有静态方法区
Cannot use this in a static context 因为:
Static方法是类方法,先于任何的实例(对象)存在。即Static方法在类加载时就已经存在了,但是对象是在创建时才在内存中生成。而this指代的是当前的对象
举个例子:
public class Test {
private static int n = 0;
public static void setNum(int n) {
this.n = n; //Cannot use this in a static context
}
public static void main(String[] args) {
setNum(0);
}
}
在方法中定义使用的this关键字,它的值是当前对象的引用.也就是说你只能用它来调用属于当前对象的方法或者使用this处理方法中成员变量和局部变量重名的情况.
而且,更为重要的是this和super都无法出现在static 修饰的方法中,static 修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象.如果使用的是类来调用而不是对象,则 this就无法指向合适的对象.所以static 修饰的方法中不能使用this.
声明为static的方法有以下几条限制:
- 它们仅能调用其他static方法
- 它们只能访问static数据
- 它们不能以任何方式引用super或this
所有对象共同的属性或者方法,那么我们可以定义为静态的。
11.main方法分析
主方法:
public static void main (String[ ] args){
//代码块
}
public:公有的,最大的访问权限
static:静态的,无需创建对象
void:表示没有返回值,无需向jvm返回结果
main:方法名,固定的方法名
String[ ] args:表示参数位字符串数组,可以在调用方法时传入参数
12.代码块
- 普通代码块
直接写在方法中的代码块就是普通代码块 - 构造块
是在类中定义的代码块,new创建对象时即被调用(构造方法也是new后即调用),优于构造方法执行 - 静态代码块
在类中使用static声明的代码块称为静态代码块
在第一次使用的时候被调用(创建对象),只会执行一次,优于构造块执行,我们在项目开发中,通常会使用静态代码块来初始化只调用一次的数据。比如说:读取配置文件 - 同步代码块(多线程中讲解)
小结:重点使用的顺序是静态代码块,普通代码块,同步代码块,构造代码块
package test;
public class test{
public static void main(String[] args){
Student s=new Student(); //构造块是在类中定义的代码块,
// new创建对象时即被调用优于构造方法执行
System.out.println("-------------");
Student s1=new Student();
}
}
class Student{
Student(){
System.out.println("我是构造方法,顺序排第一,却最后执行");
}
{
System.out.println("我是构造代码块,我排第二,我比构造方法先执行");
}
static{
System.out.println("我是静态代码块,我排最后 ,但我第一个执行。只能执行一次");
}
public void study(){
System.out.println("我是最普通的代码块");
}
}
执行结果:
13.单例设计模式
单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
- 构造方法私有(private)化,里面什么都不要写
- 创建一个本类静态对象
- 给外部提供一个公共的静态的方法getInstance(),用来获取对象实例
两种实现方式:
- 饿汉式:在类被加载后,对象立马被创建,到程序结束后释放。占用内存时间长,效率高
- 懒汉式:在第一次调用getInstance方法时,对象被创建,到程序结束后被释放。占用内存时间短。效率低(懒加载,延迟加载)
代码:
package test;
public class test{
public static void main(String[] args){
Singleton1 s1=Singleton1.getInstance();
s1.print();
Singleton2 s2=Singleton2.getInstance();
s2.print();
}
}
//饿汉式:占用内存时间长,效率高
class Singleton1{
//1.构造方法私有化,里面什么都不要写
Singleton1(){}
//2.创建一个本类静态私有化对象
private static Singleton1 s=new Singleton1();
//3.给外部提供一个公共的静态的方法,用来获取对象实例
public static Singleton1 getInstance(){
return s;
}
public void print(){
System.out.println("测试用其他的方法1");
}
}
//懒汉式:占用内存时间短。效率低(懒加载,延迟加载)
//在多线程访问时会有安全问题
class Singleton2{
private Singleton2(){}
//懒,并没有定义对象出来
private static Singleton2 s;
public static Singleton2 getInstance(){
if(s==null){
s=new Singleton2();
}
return s;
}
public void print(){
System.out.println("测试用其他方法2");
}
}
在项目中为什么要使用单例,单例有什么好处?
- 在设计一些工具类的时候(通常工具类,只有功能方法,没有属性)
- 工具类可能会被频繁调用
- 可以节省重复创建对象所带来的内存消耗,从而提高效率
能不能使用构造方法私有化+静态方法来替代单例?
格式:
如果使用构造方法私有化+静态方法来实现工具类。那么静态方法会存在方法区,加载之后就会存在,调用方便
如果使用构造方法单例,方法是普通方法,依赖对象实现。运行过程中如果方法中有参数需要进栈出栈。内存占用小。
14.对象数组与管理
点击鸡舍管理系统