1、面向对象基本概念
面向过程: 以步骤为单位,一步一步完成某个具体事情
面向对象:以对象为单位,通过调度组合不同的对象来完成某一个事情
什么是面向对象:
- 一种编程思想
- 一种思考问题的思维方式
建立面向对象思维方式:
- 先整体,在局部
- 先抽象,再具体
- 能做什么,再怎么做
如何学习面向对象:
- 掌握一门面向对象语言的语法
- 熟悉面向对象的设计原则
- 熟悉面向对象设计模式
2、类与对象
什么是类?
- 类是: 分类、类别
- 通过分类,我们可以区别不同的事务种类,在日常生活中,我们常常这样做
- 所以,类是一组具有相同特性(属性)与行为(方法)的事物集合。
3、类和对象的定义格式
class 类名称{
属性名称;
返回值类型 方法名称(){};
}
4、对象与内存分析
- new 关键字: 表示向内存申请空间,也表示实例化一个对象,创建一个对象
- 一个对象在内存中的大小,由该对象的所有属性所占内存大小的总和。引用类型变量在32位系统上占4个字节,在64位系统上占8个字节,加上而外的对象隐性数据所占的大小。
- 相同的类型才可以赋值
- 不同的引用,指向同一个对象,任何一个引用改变对象的值,其它引用都会反映出来
- 编程时要注意的问题,在确定不使用对象时,要尽早释放对象:引用=null
- 当一个堆中的对象没有被任何引用变量所指向时,该对象会被jvm 的gc程序认为是垃圾对象,从而被回收。
5、封装性
封装性的概念:
- 封装性是面向对象思想的三大特征之一
- 封装就是隐藏实现细节,仅对外提供访问接口
属性的封装、方法的封装、类的封装、组件的封装、模块化封装、系统级封装
封装的好处:
- 模块化
- 信息隐藏
- 代码重用
- 插件化易于调试
- 具有安全性
封装缺点:
会影响执行效率
方法1: 设置成员变量位private, 生成getter setter 方法
成员变量和局部变量
1、 在类中的位置不同, 成员变量在类中定义, 局部变量在方法中定义或者方法的参数
2、 在内存中的位置不同 成员变量在堆内存(成员变量属于对象,对象进堆内存)局部变量在栈内存(局部变量属于方法,方法进栈内存)
3、 生命周期不同 成员变量:随着对象的创建而存在,随着对象的销毁而消失。 局部变量: 随着方法的调用而存在,随着方法的调用完毕而消失。
4、 初始化值不同, 成员变量: 有默认初始化值,引用类型默认为null。 局部变量: 没有默认初始化值,必须定义,赋值,然后才能使用
这个意思就是:在类中 public static int aaa;
aaa 会默认初始值位0
注意: 局部变量名称可以和成员变量一样,在方法中使用的时候,采用的是就近原则
方法要放在方法区中(调用一个方法时候,方法会进栈,)
6、构造方法
构造方法就是类构造对象时调用的方法,用于对象的初始化工作
构造方法是实例化一个类的对象时,也就是new 的时候,最先调用的方法
构造方法是在类中定义的,构造方法的定义格式:方法名称与类名称相同,无返回值的声明
对象的实例化语法: Dog dog = new Dog();
Dog() 这个就是调用个构造方法
小结:
- 构造方法名称与类名相同,没有返回值声明
- 构造方法用于初始化数据(属性)
- 每一个类中都会有一个默认的无参的构造方法
- 如果类中有显示的构造方法,那么默认构造方法将失效
- 构造方法可以有多个,还想保留默认构造方法,需要显示写出来
- 构造方法可以有多个,但参数不一样,称为构造方法的重载
- 在构造方法中调用另一个构造方法,使用this( ),该句代码必须在第一句
- 构造方法之间的调用,必须要有出口
- 给对象初始化数据可以使用构造方法或setter 方法,通常情况下,两者都会保留
- 一个好的变成习惯是要保留默认的构造方法。(为了方便一些框架代码使用反射来创建对象)
- private Dog() {} , 构造方法私有化,当我们的需求是为了保证类只有一个对象时,什么时候一个类只需要一个对象?比如: 工具类(没有属性的类,只有行为)并且该工具对象被频繁使用。权衡只用一个对象与产生多个对象的内存使用,来确定该类是否要定义为只需要一个对象。
7、this 关键字
使用this 关键字完成一下操作
- 调用类中的属性
- 调用类中的方法或构造方法
- 表示当前对象
在方法中使用this调用类中的其他方法,this可以省略,this前面可以使用当前的类名,this(内部类会涉及到)
8、值传递和引用传递
public class Test{
public static void changeStr(String str){
str = "welcome";
}
public static void main(String[] args){
String = str ="1234";
changeStr(str);
System.out.println(str); // 1234
}
}
public class TestDemo
{
public static void changeStr(Demo d)
{
System.out.println("我是形参"+d); //Demo@139a55
d=new Demo();
System.out.println("我是形参"+d); //Demo@1db9742
}
public static void main(String[] args)
{
Demo d=new Demo();
System.out.println("我是实参"+d); // Demo@139a55
changeStr(d);
System.out.println("我是实参"+d); //Demo@139a55
}
}
9、对象的一对一关系
10、static 关键字
使用static 关键字修饰一个属性, 声明为static 的变量实质上就是全局变量
使用static 关键字修饰一个方法 通常,在一个类中定义一个方法为static, 那就是说, 无需本类的对象即可调用此方法
使用static 关键字修饰一个类(内部类)
静态变量在静态方法区,不在堆或栈中
- 静态变量或方法不属于对象:依赖类
- 静态变量是全局变量,生命周期从类被加载后一直到程序结束
- 静态变量只有一份,在静态方法区中存储
- 静态变量是本类所有对象共享一份
- 建议不要使用对象名去调用静态数据,直接使用类名调用
- static修饰一个方法,那么该方法属于类,不属于对象,直接用类名调用
- 静态方法不能访问非静态属性和方法,只能访问静态
限制:
- 它们仅能调用其他的static 方法
- 它们只能访问static数据
- 它们不能以任何方式引用this 或 super
所有对象共同的属性或方法,那么我们可以定义为静态的。
static 修饰的方法是静态绑定(在编译时期,类和方法的关系就确定了),
调用testB.print();方法时,子类TestB“重写”了父类TestA的静态方法,所以在编译时期,重写的static方法已经和TestB绑定在一起了,所以产生了“复写”的效果,准确来说子类static方法隐藏了父类的static方法。(子类父类都有static print方法)
但是调用test.print();时,仍旧调用的是父类TestA的方法,同样,对静态方法,在编译期就静态绑定了类和方法的关系,不存在多态性,所以静态方法的调用看等号=左边的类
构成复写的条件:方法名,参数列表,返回类型都相同。这里满足了复写的条件,然而子类方法的修饰符是static,这和多态性是相冲突的,所以会报编译错误(父类方法不是静态,子类复写的方法是静态,就会出错)
11、main 方法分析
类文件(.class) 类加载器(class loader)
方法区(Method Area) 栈(java Stacks)本地方法栈(Native Method Stacks) 堆(Heap) 程序计数器(Program Counter Register)
12、代码块
- 普通代码块, 直接写在方法中的代码块就是普通代码块, 限制局域变量的作用域。
- 构造块, 在类中定义的代码块,创建对象时,被调用,优于构造方法执行
- 在类中使用static 声明的代码块称为静态代码块,在第一次使用的时候被调用(创建对象),只会执行一次,优于构造块执行,在项目开发中,通常会使用静态代码块来初始化只调用一次的数据
13、单例设计模式
饿汉式和懒汉式区别在何时创建对象
public class Singleton{
private static volatile Singleton singleton;
private Singleton();
public static Singleton getInstance(){
if(singleton == null){
synchronized(Singleton.class){
if(singleton == null){
singleton = new Singleton;
}
}
return singleton;
}
}
}
14、对象数组与管理
package code;
import java.util.Arrays;
public class ObjectArray {
public static void main(String[] ages) {
ChichenManager cm = new ChichenManager(5);
cm.add(new Chichen(1, "小小", 10));
cm.add(new Chichen(2, "小小", 10));
cm.add(new Chichen(3, "小小", 10));
cm.add(new Chichen(4, "小小", 10));
cm.add(new Chichen(5, "小小", 10));
cm.add(new Chichen(6, "小小", 10));
System.out.println(cm.length());
System.out.println(cm.find(5));
cm.printAll();
cm.update(new Chichen(1,"大大",14));
cm.printAll();
cm.delete(1);
cm.printAll();
}
}
class ChichenManager{
private Chichen[] cs = null;
private int count = 0;
public ChichenManager(int size){
if(size > 0 )
cs = new Chichen[size];
else
cs = new Chichen[5];
}
public void add(Chichen c){
if(count >= cs.length){
int newLen = cs.length*2;
cs = Arrays.copyOf(cs,newLen);
cs[count] = c;
count++;
}else{
cs[count] = c;
count++;
}
}
public void delete(int id){
for(int i = 0; i < count; i ++){
if(cs[i].getId() == id){
for(int j = i; j < count -1; j ++){
cs[j] = cs[j+1];
}
cs[count -1] = null;
count --;
break;
}
}
}
public void update(Chichen c){
Chichen temp = find(c.getId());
if(temp != null){
temp.setName(c.getName());
temp.setAge(c.getAge());
}
}
public Chichen find(int id){
for(int i = 0; i < count; i ++){
if(cs[i].getId() == id){
return cs[i];
}
}
return null;
}
public int length(){
return cs.length;
}
public void printAll(){
for(int i =0 ; i < count; i ++){
cs[i].print();
}
}
}
class Chichen{
private int id;
private String name;
private int age;
public Chichen(){};
public Chichen(int id, String name, int age){
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void print(){
System.out.println("id="+ id + ", name="+name+",age="+age);
}
}