0. 今日内容提要
1. javabean书写规范
javabean:一个普通的类,用来描述事物的类,里面不包含任何的业务逻辑,只是用来存储数据。
比如:Teacher,Student,Mobile....(作为数据的载体)
vo,pojo,entity,model,dto。。。。
规范:
成员变量私有化
提供get和set方法
提供无参构造方法
提供有参构造方法
自动生成get和set方法:
右键-->source-->generate getters and setters-->select All-->OK
自动生成构造方法:
右键-->source-->generate constructor using fields-->selectALL/deSelectAll-->OK
案例:
编写javabean:
商品编号
商品名称
商品价格
商品数量
public class Product {
/**
* 商品编号
*/
private int proId;
/**
* 商品名称
*/
private String proName;
/**
* 商品价格
*/
private double proPrice;
/**
* 商品数量
*/
private int proCount;
public int getProId() {
return proId;
}
public void setProId(int proId) {
this.proId = proId;
}
public String getProName() {
return proName;
}
public void setProName(String proName) {
this.proName = proName;
}
public double getProPrice() {
return proPrice;
}
public void setProPrice(double proPrice) {
this.proPrice = proPrice;
}
public int getProCount() {
return proCount;
}
public void setProCount(int proCount) {
this.proCount = proCount;
}
public Product() {
}
public Product(int proId, String proName, double proPrice, int proCount) {
super();
this.proId = proId;
this.proName = proName;
this.proPrice = proPrice;
this.proCount = proCount;
}
public static void main(String[] args) {
Product d1 = new Product();
d1.proId = 1;
d1.proName="辣条";
d1.proPrice = 3;
d1.proCount = 100;
Product d2 = new Product();
d2.setProId(2);
d2.setProName("火腿肠");
d2.setProPrice(1);
d2.setProCount(400);
Product d3 = new Product(3,"老干妈",6.5,300);
}
}
2. 同名局部变量和成员变量的调用问题
public class Person {
String name = "张三";
// 方法一
public void print() {
System.out.println(name);
}
// 方法二
public void print(String name) {
System.out.println(name);
}
// 方法三
public void print1(String name) {
System.out.println(this.name);
}
public static void main(String[] args) {
Person p = new Person();
System.out.println(p.name);//张三,因为成员变量有初始值,就是张三
p.name = "李四";
p.print();//李四,因为成员变量已经被改成了李四
p.print("王五");// 王五,因为就近原则,默认使用局部变量
p.print1("赵六");// 李四,使用this调用的还是成员变量,成员变量是李四
}
}
3. static 关键字
静态的方法中只能调用外部用static修饰的变量和方法,如果非要调用非静态的,需要创建对象。原因是静态的变量或方法,最先加载到内存中,而成员变量或是成员方法只能在创建新对象后才会在堆中产生。如果此时没有对象,那么成员变量或成员方法还不存在,所以不能调用。
静态变量和成员变量到底有什么区别?
静态变量只有一个,其被所有对象共享,而成员变量则不一样,每个对象都会有自己的成员变量,如下图,黄色是静态变量,车把等就是成员变量对象o和对象o1都有自己的成员变量
简述static关键字
static可以用来修饰变量和方法,被static修饰的变量和方法就变成了静态变量和静态方法。随着类的加载而加载,先于对象的存在,被所有的对象所共享,可以使用类名词调用,也可以使用对象调用,推荐使用类名调用,静态的方法中只能调用外部用static修饰的变量和方法
成员变量:对象名调用 对象名.成员变量 如 p.name;
静态变量:类名调用 类名.静态变量 如 StaticDemo.b
成员变量:也叫实例变量 实例-----对象
静态变量: 也叫类变量
案例
public class StaticDemo {
int b;//成员变量
static int a;
public static void main(String[] args) {
// static int c=1; 注意局部变量不能用static来修饰
System.out.println(a);
System.out.println(b);//此处会报错,因为b是成员变量,而此打印操作是在静态方法中进行
}
}
运行结果如下图
如果非要在静态方法中调用非静态的事务,只能创建对象,如下
public class StaticDemo {
int b;//成员变量
static int a;
public static void main(String[] args) {
System.out.println(a);
StaticDemo sd = new StaticDemo();
System.out.println(sd.b);
}
}
4. 代码块
(1)静态代码块:
static{ } 随着类的加载而执行一次
public class CodeBlockDemo {
static {
System.out.println("我是静态代码块");
}
public static void main(String[] args) {
}
}
// 运行结果: 我是静态代码块
原因:main方法一启动,类就要加载,类一加载,静态代码块就会执行
(2)构造代码块
{ } 每创建一个对象就会执行一次
注意:静态代码块先于构造代码块,先于构造方法执行
(3)局部代码块:
定义在方法中的{ } 局部代码块执行完毕后会立马释放,局部代码块很少使用,但当方法中有一部分代码很耗内存,当其执行完不释放掉的话,后面代码运行效率很低,这时就可以用局部代码块来写这些代码
public class CodeBlockDemo {
static {
System.out.println("我是静态代码块");
}
{
System.out.println("我是构造代码块");
}
public CodeBlockDemo() {
System.out.println("我是无参构造方法");
}
public CodeBlockDemo(String a) {
System.out.println("我是有参构造方法");
}
public static void main(String[] args) {
CodeBlockDemo c1 = new CodeBlockDemo();//当没创建此对象时,运行的结果只有 “我是代码块”,说明构造方法和构造代码块只能是创建了对象才会产生
}
}
运行结果: 我是代码块 我是构造方法 我是无参构造方法
由下面的代码可看出静态代码块先于构造代码块,先于构造方法执行
public class CodeBlockDemo {
public CodeBlockDemo() {
System.out.println("我是无参构造方法");
}
public CodeBlockDemo(String a) {
System.out.println("我是有参构造方法");
}
{
System.out.println("我是构造代码块");
}
static {
System.out.println("我是静态代码块");
}
public static void main(String[] args) {
CodeBlockDemo c = new CodeBlockDemo();
CodeBlockDemo c1 = new CodeBlockDemo("a");
}
}
运行结果(并没按照代码顺序进行打印)
练习
统计一个类中创建对象的个数
此处利用构造代码块来做,构造方法也行,但没构造代码块合适,因为无论是有参对象还是无参对象构造代码块都会执行
public class CountObject {
static int count = 0;
{
count ++;
}
public static void main(String[] args) {
CountObject c1 = new CountObject();
CountObject c2 = new CountObject();
CountObject c3 = new CountObject();
// CountObject c4 = new CountObject();
System.out.println("创建对象的个数为"+ count);//3
}
}
5. 继承
(1)格式:
class 子类名 extends 父类名{ }
被继承的类叫做父类,基类或超类;继承的类叫子类或派生类
(2)注意事项
java中的继承只支持单继承,不支持多继承(即一个子类只能有一个父类),但其支持多层继承
object:(万类之祖)如果一个类没有继承任何类,那么它默认继承自Object
父类中的私有变量或方法不能被继承
案例
1 public class ExtendsDemo {
2 public static void main(String[] args) {
3 Student s = new Student();
4 System.out.println(s.age);
5 System.out.println(s.height); //此行代码可正常运行,表示java中的继承可以多层继承
6 s.eat();
7
8 }
9 }
10 class SuperPerson {
11 double height;
12 }
13 class Person extends SuperPerson{
14 String name;
15 int age;
16 char gender;
17 public void eat() {
18 System.out.println("吃嘛嘛香");
19 }
20 }
21 class Student extends Person{
22 double score;
(3)同一个文件中定义多个类
一个文件中可以定义多个类,但必须只能有一个类使用public类,并且要用public修饰的类必须和文件名相同,此外main方法也必须定义在用public修饰的类中(定义在非public修饰的类中无法执行)
同一个包中不能定义名字相同的类
练习
定义一个Dog
包含name gender furColor lookDoor()
定义Dog的子类Dog:
眼睛的颜色eyeColor
定义Dog的子类:UsaDog
weight; age
创建一个Dog对象,并赋值;创建一个UsaDog,并赋值
1 public class DogTest {
2 public static void main(String[] args) {
3 Dog cd1 = new Dog();
4 cd1.eyescolor = "黑色";
5 cd1.furColor = "黄色";
6 cd1.gender = '公';
7 cd1.name = "小黄";
8 System.out.println(cd1.name+cd1.gender+cd1.furColor+cd1.eyescolor);
9 }
10 }
11
12 class Dog {
13 String name;
14 char gender;
15 String furColor;
16 public void lookDoor() {
17 System.out.println("看门");
18 }
19 }
20 class Dog extends Dog{
21 String eyescolor;
22 }
23
24 class UsaDog extends Dog{
25 double weight;
26 int age;
27 }
5.4 继承中成员变量的关系
当调用某子类变量时,先在子类中找,再去父类中找,父类中没有就报错
5.5 super关键字
super:可以看做是父类中的一个引用(指代父类中的对象),用与区分子类中和父类中同名的成员(成员变量,成员方法),super指代的是父类中的值,只能在之类中使用
this:可以看做是本类中的一个对象,用于区分同名的局部变量和成员变量,this指代的是成员变量,只能在本类中使用
this和super后面可以跟成员变量和成员方法(不能是局部变量)
this.成员变量 this.成员方法()
super.成员变量 this.成员方法()
调用构造方法:
this(参数):调用本类中的构造方法
super(): 调用父类中的构造方法
this和super不能用于static方法中
原因:静态方法先于对象产生,而this和super指代对象,在静态方法中,对象都还没产生,所以this和static不能用于static方法中
5.6 继承中构造方法的关系
子类中的构造方法会默认调用父类中无参数的构造方法,如果父类中没有无参数的构造方法,子类必须直接或简介的调用父类中的构造方法
如下代码子类会默认调用父类构造方法
1 //创建测试类
2 public class ExtendsConstrutorDemo {
3 public static void main(String[] args) {
4 SonClass s1 = new SonClass();
5 }
6 }
7 // 创建一个父类
8 class FatherClass {
9 public FatherClass() {
10 System.out.println("我是父类无参构造方法");
11 }
12 }
13 // 创建子类
14 class SonClass extends FatherClass{
15 public SonClass() {
16 // 此处默认会有super(),用来调用父类构造方法,只能放第一行
17 System.out.println("我是子类无参构造方法");
18 }
19 }
打印结果为
若第9行的代码中,父类构造方法加参数,变成如下
public FatherClass(String str){
这样的话,子类中调用父类构造方法处就会报错(提示无父类构造方法,即super()调用不到父类中的构造方法)
解决办法:
第一种:直接调用:
在super()中加一个参数即可,如super(“str”)
第二种:间接调用
在本类中再写一个有参的构造方法,利用this调用这个有参的构造方法,部分代码如下图
调用本类中的构造方法:
this(参数值);此也一定要放到第一行,和super()一样
为什么要调用父类的构造方法?
子类要继承父类中的数据,父类中有时候会有些成员变量和成员方法,而要调用父类中的数据,父类就要将这些数据初始化(即将这些数据创建好),而调用父类造方法,就能达到父类数据初始化的效果。
练习
/**
* 构建一个父类,两个子类
* 1.构造两个父类中和子类中名字一样的属性和方法,属性赋不同的值
* 分别用父类和子类的对象调用
* 2.为父类和子类提供无参构造方法,并显示调用super();
* 3.为子类提供有参构造方法1,并显示调用本类中的无参构造方法this();
* 4.为子类提供有参构造方法2,并显示调用父类中的构造方法
* 5.为父类提供有参数构造方法,在子类中构造方法中调用
*/
package com._51doit.javase.day08;
public class ExtendsTest1 {
public static void main(String[] args) {
FuClass f1 = new FuClass();
System.out.println(f1.name);//
NvClass n1 = new NvClass(4);
n1.sleep();
}
}
class FuClass{
String name = "老张";
public FuClass() {
super();//调用Object中的构造方法
}
public void sleep() {
System.out.println("生前何须久睡死后自会长眠");
}
public FuClass(int a) {
}
}
class ZiClass extends FuClass{
public ZiClass() {
super();
}
public ZiClass(int a) {//有参
this();//调用本类中无参构造方法
}
String name = "大张";
public void sleep() {
System.out.println("中午不睡下午崩溃");
}
}
class NvClass extends FuClass{
String name = "小张";
public NvClass(int b) {
super(1);//调用父类中有参的构造方法
}
/*public void sleep() {
System.out.println("别睡太晚,梦会太短");
}*/
}
5.7 继承中成员方法的关系
与成员变量相似,先在子类中找,再去父类中找,父类中没有就报错
5.8 方法的重载和方法的重写
概念:
重写(override):子类中出现了和父类中方法名一样,返回值类型,参数列表一样的方法,就叫做方法的重写
重载(overload):一个类中可以存在多个名字相同的方法,但是必须保证参数的个数或类型不同,与返回值无关
注解:@override 可以使用该注解验证重写格式是否正确,把它写到子类的方法上
如:
方法重写的注意事项
1. 父类中的私有方法不能被重写(子类中可以有同名的方法,只是此种情况不叫方法的重写)
2. 子类重写父类中的方法,访问权限不能更低(权限一次减小:public default protected private)
3. 静态的方法不能重写
练习题
按要求编写一个Java 应用程序:
(1)编写一个矩形类Rect,包含:
矩形的宽width;矩形的高height。
两个构造方法:
1.一个带有两个参数的构造方法,用于将width 和height 属性初化;
2.一个不带参数的构造方法,将矩形初始化为宽和高都为10。
两个方法:
求矩形面积的方法area()
求矩形周长的方法perimeter()
(2)通过继承Rect 类编写一个具有确定位置的矩形类PlainRect,其确定位置用
矩形的左上角坐标来标识,包含:
添加两个属性:矩形左上角坐标startX 和startY。
两个构造方法:
带4 个参数的构造方法,用于对startX、startY、width 和height 属性
初始化;
不带参数的构造方法,将矩形初始化为左上角坐标、长和宽都为0
的矩形;
添加一个方法:
判断某个点是否在矩形内部的方法isInside(double x,double y)。如在矩
形内,返回true, 否则,返回false。
提示:点在矩形类是指满足条件:
x>=startX&&x<=(startX+width)&&y<=startY&&y>=(startY-height)
(3)编写PlainRect 类的测试程序
创建一个左上角坐标为(10,10),长为20,宽为10 的矩形对象;
计算并打印输出矩形的面积和周长;
判断点(25.5,13)是否在矩形内,并打印输出相关信息。
6. final
final 可以用来修饰类,方法,变量
final 修饰的类不能被继承
final 修饰的方法不能被重写
final 修饰的变量值不能改变,final修饰的变量要有初始值
一般我们创建常量:public static final
final: 限制值不能变
static: 只有一份
两种文法
final static
final finally finalize
7. 单例设计模式
概述:一个类只产生一个实例对象
分类:饱汉式
懒汉式
实现步骤:
1. 私有构造方法
2. 创建最终静态对象
3. 提供公共的访问对象
如何实现一个类只能创建一个对象?
正常情况创建对象的形式为:类名 对象名 = new 类的构造方法
思路:将构造方法属性变为私有,即用private修饰,这样外部类就不能通过 new 类构造方法来创建对象了。但自己可以在类的内部创建一个公有的对象(即为成员变量,加上static就变成静态变量,此处因为是各个类公有,所以为应该为静态变量),供外部类调用。
如下:
1 public class Singleton {
2 public static void main(String[] args) {
3 Singleton1 s1 = Singleton1.s;// 通过类调用静态变量s得到一个对象
4 Singleton1 s2 = Singleton1.s;
5 System.out.println(s1 == s2);
6 }
7 }
8
9
10 class Singleton1 {
11 public static Singleton1 s = new Singleton1();//此处一定要加static,让Singleton1类型的s成员变量变成静态变量,不然只能通过对象调用,不能类调用。
12 private Singleton1() {
13 }
14 }
运行结果为true,说明对象s1和对象s2是同一个对象
但这种直接获取成员变量的形式不好,应该通过创建方法的形式,如下(也称饱汉式)
public class Singleton {
public static void main(String[] args) {
Singleton1 s1 = Singleton1.getInstance();
Singleton1 s2 = Singleton1.getInstance();
System.out.println(s1 == s2);
}
}
class Singleton1 {
public static Singleton1 s = new Singleton1();
// 创建一个静态的访问方法,返回本类中唯一的对象
public static Singleton1 getInstance() { //此处的Singleton1表示返回Singleton1类型的值
return s;
}
private Singleton1() {
}
}
运行结果 true
懒汉式
由于懒汉式一开始就创立了一个对象,即在堆中占据了一个内存空间,若其他类一直没有去调用这个获取对象的方法,这样就很浪费资源,所以就有懒汉式的出现
public class Singleton2 {
public static void main(String[] args) {
Singleton3 s1 = Singleton3.getInstance();
Singleton3 s2 = Singleton3.getInstance();
System.out.println(s1);
}
}
class Singleton3{
public static Singleton3 s;
public static Singleton3 getInstance() {
if(s==null) {
s = new Singleton3();
}
return s;
}
private Singleton3() {
}
}
懒汉式也存在问题,会有线程安全问题(创建多个对象),如:
当一个线程Thread1刚执行完if判断语句时,cpu切换至另一个线程,此线程一直执行完,创建了一个s对象,此时cpu又切换回去执行线程Thread1,此时就又会创建一个s对象,这样就会创建多个对象(如果有多个线程)
解决方法,上一把锁,使用同步方法解决(即在方法的修饰符位置加上synchronized),如下:
public synchronized static Singleton3 getInstance()