JVM内存分配:方法区、栈、堆、常量池
怎么得到一个对象
new 自己建的类 (自己创建的)
通过某个对象,调用其方法,得到其他对象(程序提供的)
通过类的静态方法,得到某个对象 (程序提供的)
拉姆达表达式(lambda)匿名函数
Lambda 表达式(lambda expression)是一个匿名函数,即没有函数名的函数
能够使用 Lambda 表达式的一个重要依据是必须有相应的函数接口。
所谓函数接口,是指内部有且仅有一个抽象方法的接口。
函数式接口 @FunctionalInterface
@FunctionalInterface , 函数式接口
接口内部,必须的只有一个抽象方法
只能修饰interface接口,不能修饰抽象类或者类
@FunctionalInterface
abstract class B{ public abstract void f();}
/B is not a functional interface 编译错误
@FunctionalInterface 只能修饰 interface接口
多个函数式接口的代码
@FunctionalInterface
//函数式接口 注解 接口内部,有且仅有一个抽象方法
//@FunctionalInterface 只能修饰 interface接口
interface Demo1AInterface {
//计算两个数之和
int sum(int x,int y);
}
//B is not a functional interface 编译错误
//@FunctionalInterface 只能修饰 interface接口
//@FunctionalInterface
//abstract class B{
// public abstract void f();
//}
interface BInterface{
//判断是否大于18
boolean isBigPeople(int age);
}
interface CInterface{
//输出格式: name+","+word
void sayHi(String name,String word);
}
interface DIterface{
//产生一个随机整数
int randomInt();
}
实现接口的三种方式
匿名内部类创建接口对象
匿名内部类,可用于一个接口有一个或一个以上抽象方法时,对接口创建对象
class TestNiMIngClass {
public static void main(String[] args) {
Demo1AInterface a = new Demo1AInterface() {
@Override
public int sum(int x, int y) {
return x + y;
}
};
System.out.println("求和:" + a.sum(3, 9));
BInterface b = new BInterface() {
@Override
public boolean isBigPeople(int age) {
return age >= 18;
}
};
System.out.println(b.isBigPeople(20));
CInterface c = new CInterface() {
@Override
public void sayHi(String name, String word) {
System.out.println(name + "," + word);
}
};
c.sayHi("李华", "你好");
DIterface d = new DIterface() {
@Override
public int randomInt() {
return new Random().nextInt();
}
};
System.out.println("随机生成的整数为:" + d.randomInt());
}
}
lambda表达式的使用
必须满足接口中只有一个抽象方法,才能使用
若DIterface有两个抽象方法
interface DIterface{
//产生一个随机整数
int randomInt();
//指定范围的随机生成
int randomInt(int d);
}
此时DIterface接口不符合lambda语法规则[符合函数式表达式]
只能使用匿名内部类来重写
DIterface dIterface=new DIterface() {
@Override
public int randomInt() {
return new Random().nextInt(10);
}
@Override
public int randomInt(int bound) {
return new Random().nextInt(bound);
}
};
lambda表达式必须满足接口中只有一个抽象方法,才能使用
函数参数格式(省略函数名字,省略参数类型 改变参数名字,确保参数个数)->{函数体}
lambda表达式 与引用类型绑定在一起的
参数名任意,但参数个数必须匹配的上
(a, b) -> {return a + b;}; 是个对象
Demo1AInterface aInterface = (a, b) -> { return a + b; }; 即将创建对象赋值给一个类型相同的引用变量
class TestLambda {
public static void main(String[] args) {
//lambda表达式 对应的接口必须符合函数式接口特征[只有唯一一个抽象方法]
//函数参数格式(省略函数名字,省略参数类型 改变参数名字,确保参数个数)->{//函数体}
//若无参函数,直接写();若有参函数,写(参数名 参数个数必须相同)
//lambda表达式 与引用类型绑定在一起的
Demo1AInterface aInterface = (a, b) -> {
//参数名任意,但参数个数必须匹配的上
//内部把a,b当接口中方法定义类型使用a、b(int类型)
return a + b;
};//(a, b) -> {return a + b;}; 是个对象
System.out.println("求和:" + aInterface.sum(9, 3));
BInterface bInterface=(h)->{
return h>=18;
};
System.out.println(bInterface.isBigPeople(17));
CInterface cInterface=(n,w)->{
System.out.println(n+","+w);
};
cInterface.sayHi("ll","HI");
//DIterface接口不符合lambda语法规则[符合函数式表达式]
//只能使用匿名内部类来重写
// DIterface dIterface=new DIterface() {
// @Override
// public int randomInt() {
// return new Random().nextInt(10);
// }
//
// @Override
// public int randomInt(int bound) {
// return new Random().nextInt(bound);
// }
// };
DIterface dIterface=()->{
return new Random().nextInt(100);
};
System.out.println("随机生成的整数为:" + dIterface.randomInt());
}
}
强制转,无需再赋值给引用类型的变量
System.out.println("求和: "+((Demo1AInterface)(a,b)->{
return a+b;
}).sum(4,6));
例子二
class H{
int k(Demo1AInterface a,int x,int y){
return a.sum(x,y);
};
boolean b(BInterface b,int age){
return b.isBigPeople(age);
}
void c(BInterface b,DIterface d){
int r=d.randomInt();
boolean b1=b.isBigPeople(r);
if(b1)
System.out.println("成年人");
else
System.out.println("未成年人");
}
}
调用该类的方法
public class TestLambda2 {
public static void main(String[] args) {
H h = new H();
int he = h.k((a1, b1) -> {
return a1 + b1;
}, 4, 6);
System.out.println("he:" + he);
boolean b2 = h.b((h2) -> {
return h2 >= 18;
}, 17);
//调用c
//方法调用: 参数类型,参数个数,参数返回值
//方法定义: 方法签名(方法修饰符,返回值,方法名,参数) 方法体怎么写
h.c((b3) -> {
return b3 >= 18;
}, () -> {
return new Random().nextInt(20);
});
}
}
接口default 修饰方法,实现方法
jdk8之后,接口中可使用default修饰方法 写方法的实现 default修饰的方法 必须有方法体
若DIterface类加入default int randomInt(int d)已实现的方法
interface DIterface{
//产生一个随机整数
int randomInt();
//指定范围的随机生成
//default修饰的方法 必须有方法体
default int randomInt(int d){
return new Random().nextInt(d);
}
}
public class TestLambda3 {
public static void main(String[] args) {
DIterface d=()->{
return new Random().nextInt();
};
System.out.println("100以内的随机整数:"+d.randomInt(15));
}
Object 是所有类的父类
定义class时 若未明确指明父类 则该类的父类就是Object
一般省略extends Object
Object 是所有类的父类,该类封装了类型中常用的属性和方法
继承hashCode方法
toString()
toString 显示成员变量的值[一般重写]
输出语句 输出某个引用的时候 本质调用了toString方法
//定义class时 若未明确指明父类 则该类的父类就是Object,一般省略extends Object
//Object 是所有类的父类,该类封装了类型中常用的属性和方法
public class Demo2Piont extends Object {
int x;
int y;
public Demo2Piont(){
super(); //省略
}
public void up(){
y++;
}
}
class TestPiont{
public static void main(String[] args) {
Class pointClass=Demo2Piont.class; //class是继承的
Demo2Piont p=new Demo2Piont();
Class pClass=p.getClass();//继承父类的getClass()方法
//可继承;可重写
//toString 显示成员变量的值[一般重写]
String str=p.toString();//继承的toString;
System.out.println(str);//day5.PointObject@43a25848
System.out.println(p);//day5.PointObject@43a25848
//输出语句 输出某个引用的时候 本质调用了toString方法
int code=p.hashCode();//继承hashCode方法
//一般重写equals方法
//自定义比较规则[一般比较属性值是否相同]
boolean b=p.equals(p);//继承父类的equals方法
System.out.println(b);
}
}
重写equals()方法
一般重写equals方法 自定义比较规则[一般比较属性值是否相同]
==
基本数据类型 判断数据值是否相同 ; 引用类型 判断引用类指向的地址是否相同[即是否为同一个对象]
equals()
父类Object中的一个方法 指定两个对象是否相等的比较规则[两个对象属性值]
默认比较两个对象地址是否相同 子类重写父类equals()方法
两个对象比较equals为true,只能说明属性值相等 但不能说明是同一个对象[String]
//== 基本数据类型 判断数据值是否相同 ; 引用类型 判断引用类指向的地址是否相同[即是否为同一个对象]
//equals 父类Object中的一个方法 指定两个对象是否相等的比较规则[两个对象属性值]
//默认比较两个对象地址是否相同 子类重写父类equals()方法
//两个对象比较equals为true,只能说明属性值相等 但不能说明是同一个对象[String]
public class Demo3Shape {
int x;
int y;
public Demo3Shape(){
}
//重写toSting()
public String toString(){
return this.getClass()+"("+x+","+y+")";
}
//重写equals 比较两个点的值是否相等
//自定义比赛规则
public boolean equals(Object o){//重写
//若null 则不等
//若类型不同 则不等
//若自己 说明相等
//若类型相同 不是自己 则判断属性值是否相等
if(o==null)
return false;
else {
if(!(o.getClass()==this.getClass()))
return false;
else {
if(o==this) //引用地址是否相等
return true;
else {
//向下转换 强制数据类型转换
if(o instanceof Demo3Shape){
Demo3Shape s=(Demo3Shape)o;
if(s.x==this.x&&s.y==this.y)
return true;
}
return false; //不符合以上条件 说明不相等
}
}
}
}
}
class TestShape{
public static void main(String[] args) {
Demo3Shape s1=new Demo3Shape();
s1.x=5;
s1.y=10;
Demo3Shape s2=new Demo3Shape();
s2.x=5;
s2.y=10;
Demo2Piont p=new Demo2Piont();
p.x=5;
p.y=10;
//输出语句 输出某个引用的时候 本质调用了toString方法
System.out.println("========toString=======");
System.out.println(s1);
//class day5.Demo3Shape(5,10)
System.out.println(s2.toString());
//class day5.Demo3Shape(5,10)
System.out.println(p.toString());
//day5.Demo2Piont@60addb54
System.out.println("==");
System.out.println(s1==s1);//true
System.out.println(s1==s2);//false
System.out.println("=====equals=====");
System.out.println(s1.equals(s1));//true
System.out.println(s1.equals(s2));//true
System.out.println(s1.equals(p));//false
}
String类型中对父类equals()进行过重写
String a1="a";
String a2="abc";
String a3=new String("a");
String a4=new String("abc");
String a5="abc";
//String重写了equals()方法,用于比较值是否相等
System.out.println("=====String====");
System.out.println(a1==a2);//false
System.out.println(a1==a3);//false
System.out.println(a2==a3);//false
System.out.println(a2==a4);//fasle
System.out.println(a2==a5);
//true 字符串常量池相同对象
System.out.println(a2.equals(a3));//false
System.out.println(a2.equals(a4));//true 对象不同 数据值相同
Objects.equals()工具方法
Objects.equals()工具方法 提供的方法函数 对两个对象进行判断等值判断
Objects.equals()提供的方法函数
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
本质 还是会调用到定义的类的equals()方法
若重写过,以重写过的equals()方法为准
若未重写,则默认使用父类的equals()方法[比较两个对象的地址是否相等]
public class TestObjects {
public static void main(String[] args) {
//在Demo2Piont类中未重写过equals()方法
//则默认使用父类的方法[比较两个对象的地址是否相等]
boolean b=Objects.equals(p1,p2);
System.out.println("p1->p2: "+b);//p1->p2: false
}
}
静态代码块
类中的代码块可以使用static修饰,则被称为静态代码块
若有代码,需在类加载前执行,则将代码块放入静态代码块中(静态代码块只执行一次)
非静态代码块[匿名代码块] 优先于构造器的调用[编译后 匿名代码块放置构造函数首位]
若代码块,需要在创建对象之前(构造器的首位)执行,则将代码块放入非静态代码块(非静态代码块[匿名代码块]执行n次)
public class StaticBlockDemo {
public static void main(String[] args) {
// ** 静态代码块,优先于静态方法的调用
// *** 如果有什么代码,需要在类加载的时候,就执行,把这个代码放在静态代码块中(静态代码块只执行一次。)。
Foo.show(); // -- 通过类名,直接调用静态方法。
// ** 非静态代码,优先余构造函数内部的其他代码的执行。
// *** 如果有代码,希望在调用构造函数的其他代码,都要先执行,可以使用非静态代码块(非静态代码块执行多次)。
Foo f = new Foo();
Foo f1 = new Foo();
}
}
class Faa{
}
class Foo extends Faa{
public Foo(){
super();
System.out.println("构造器函数");
}
{ // 经过编译,这个内容,就放在了构造函数的内部代码之前了。
System.out.println("非静态代码块");
}
static {
System.out.println("这个是静态代码块");
}
public void print(){
System.out.println("这个是普通方法");
}
public static void show(){
System.out.println("这个是静态方法。");
}
}
封装
//面向对象三大特性
//封装 通过private关键字对成员变量修饰 提供getter和setter方法对成员变量进行取值与赋值
//继承 A类通过extends关键字,继承B类;java单继承 一个子类只能有一个父类,一个父类有多个子类
//继承提供代码的重用性
//多态 对象具备多种状态 向上造型
public class Demo4FengStudent {
private int age;
private String hobby;
private String name;
private String sex;
//自动生成get/set 鼠标右击[Alt+insert]、Generate..选项
//set 给成员变量赋值 有参数,无返回值
//get 获取成员变量的值 无参数,有返回值
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
class TestStudent{
public static void main(String[] args) {
Demo4FengStudent fS=new Demo4FengStudent();
fS.setAge(12);
fS.setName("LZH");
fS.setHobby("追剧");
fS.setSex("男");
System.out.println("输出成员变量");
System.out.println(fS.getAge()+","+fS.getName()+","+fS.getHobby()+","+fS.getSex());//12,LZH,追剧,男
}
}
面向对象三大特性
封装,对象的成员变量尽量使用private私有进行修饰,将其属性和方法结合为一个独立的整体,并尽可能隐藏对象的内部实现细节
继承,多个子类中重复的代码抽取到父类中,子类通过extends关键字继承父类,可以直接使用,减少代码重复,提高代码的复用性
多态,对象具有多种状态,即向上造型,提高代码的可扩充性。