混合型数组的理解与使用

By heiry on 2019-04-21 [ in 技术 ]

一. 在同一数组变量中,索引关联同时并存时的索引引用规律:

PHP中数组分索引数组与关联数组,并且索引数组与关联数组能同时共存,例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$myarray = array("foo","bar","site"=>"mosang",123);
$myarray = array("foo","bar","site"=>"mosang",123);
$myarray = array("foo","bar","site"=>"mosang",123);

我们var_dump该数组变量,结果如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
array(4) { [0]=> string(3) "foo" [1]=> string(3) "bar" ["site"]=> string(6) "mosang" [2]=> int(123) }
array(4) { [0]=> string(3) "foo" [1]=> string(3) "bar" ["site"]=> string(6) "mosang" [2]=> int(123) }
array(4) { [0]=> string(3) "foo" [1]=> string(3) "bar" ["site"]=> string(6) "mosang" [2]=> int(123) }

可以看到,该数组中的关联项”site”=>”mosang”并没有占用数组下标,下标引用最大值是2。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
echo $myarray[0]."<br>";
echo $myarray[1]."<br>";
echo $myarray[2]."<br>";
echo $myarray[0]."<br>"; echo $myarray[1]."<br>"; echo $myarray[2]."<br>";
echo $myarray[0]."<br>";
echo $myarray[1]."<br>";
echo $myarray[2]."<br>";

输出结果(并没有“mosang”值):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
foo
bar
123
foo bar 123
foo
bar
123

二. 关联数组中的key如果为整数字符串,则key自动转化为数组索引值:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$mixarray = array("60"=>"mosang.net",88,"heiry");
var_dump($mixarray);
//输出如下:
array(3) { [60]=> string(10) "mosang.net" [61]=> int(88) [62]=> string(5) "heiry" }
$mixarray = array("60"=>"mosang.net",88,"heiry"); var_dump($mixarray); //输出如下: array(3) { [60]=> string(10) "mosang.net" [61]=> int(88) [62]=> string(5) "heiry" }
$mixarray = array("60"=>"mosang.net",88,"heiry");
var_dump($mixarray);

//输出如下:
array(3) { [60]=> string(10) "mosang.net" [61]=> int(88) [62]=> string(5) "heiry" }

可以看出,key“60”自动转成了数组索引,并且之后的索引值在此基础上增加。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$mixarray = array(88,"60"=>"mosang.net","heiry");
var_dump($mixarray);
//输出结果如下
array(3) { [0]=> int(88) [60]=> string(10) "mosang.net" [61]=> string(5) "heiry" }
$mixarray = array(88,"60"=>"mosang.net","heiry"); var_dump($mixarray); //输出结果如下 array(3) { [0]=> int(88) [60]=> string(10) "mosang.net" [61]=> string(5) "heiry" }
$mixarray = array(88,"60"=>"mosang.net","heiry");
var_dump($mixarray);
//输出结果如下
array(3) { [0]=> int(88) [60]=> string(10) "mosang.net" [61]=> string(5) "heiry" }

这种情况下,我们不能以数组长度for循环遍历。

三.手动指定数组索引,如果该索引值与之前相同,则之前的值会被覆盖:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$mixarray_2 = array("first","second","0"=>"third");
var_dump($mixarray_2);
//输出结果如下
array(2) { [0]=> string(5) "third" [1]=> string(6) "second" }
$mixarray_2 = array("first","second","0"=>"third"); var_dump($mixarray_2); //输出结果如下 array(2) { [0]=> string(5) "third" [1]=> string(6) "second" }
$mixarray_2 = array("first","second","0"=>"third");
var_dump($mixarray_2);
//输出结果如下
array(2) { [0]=> string(5) "third" [1]=> string(6) "second" }

可见:该数组实际上只有两个元素,原索引0值“first”的元素已经被覆盖。

count统计时会统计两种数组的总个数,因此混合数组中,不能使用for循环来遍历(造成越界)。

四. 混合数组的强制类型转换

——包含有合法整型值的字符串会被转换为整型。例如键名 “8” 实际会被储存为 8。但是 “08” 则不会强制转换,因为其不是一个合法的十进制数值。

——浮点数也会被转换为整型,意味着其小数部分会被舍去。例如键名 8.7 实际会被储存为 8

——布尔值也会被转换成整型。即键名 true 实际会被储存为 1 而键名 false 会被储存为 0

——Null 会被转换为空字符串,即键名 null 实际会被储存为 “”

——数组和对象不能被用为键名。坚持这么做会导致警告:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$array = array(
1 => "a",
"1" => "b",
1.5 => "c",
true => "d",
);
var_dump($array);
$array = array( 1 => "a", "1" => "b", 1.5 => "c", true => "d", ); var_dump($array);
$array = array(
    1    => "a",
    "1"  => "b",
    1.5  => "c",
    true => "d",
);
var_dump($array);

输出结果:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
array(1) {
[1]=>
string(1) "d"
}
//所有的键名都被强制转换为 1,则每一个新单元都会覆盖前一个的值,最后剩下的只有一个 "d"
array(1) { [1]=> string(1) "d" } //所有的键名都被强制转换为 1,则每一个新单元都会覆盖前一个的值,最后剩下的只有一个 "d"
array(1) {
  [1]=>
  string(1) "d"
}
//所有的键名都被强制转换为 1,则每一个新单元都会覆盖前一个的值,最后剩下的只有一个 "d"

五.同一个数组元素,只能有一种有效访问方式(数组下标和者关联名称其中之一):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$myarray = ["student1"=>"迪丽热巴","student2"=>"马尔扎哈","student3"=>"古力娜扎"];
foreach ($myarray as $item => $value){
echo "key为{$item}的值是:{$value}<br>";
}
echo "第一个学生的姓名为:".$myarray[0];
$myarray = ["student1"=>"迪丽热巴","student2"=>"马尔扎哈","student3"=>"古力娜扎"]; foreach ($myarray as $item => $value){ echo "key为{$item}的值是:{$value}<br>"; } echo "第一个学生的姓名为:".$myarray[0];
$myarray = ["student1"=>"迪丽热巴","student2"=>"马尔扎哈","student3"=>"古力娜扎"];
foreach ($myarray as $item => $value){
    echo "key为{$item}的值是:{$value}<br>";
}
echo "第一个学生的姓名为:".$myarray[0];

输出结果:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
key为student1的值是:迪丽热巴
key为student2的值是:马尔扎哈
key为student3的值是:古力娜扎
第一个学生的姓名为:
key为student1的值是:迪丽热巴 key为student2的值是:马尔扎哈 key为student3的值是:古力娜扎 第一个学生的姓名为:
key为student1的值是:迪丽热巴
key为student2的值是:马尔扎哈
key为student3的值是:古力娜扎
第一个学生的姓名为:

可见都是关联数组,使用下标不能访问到元素。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$myarray = ["student1"=>"迪丽热巴","马尔扎哈","student3"=>"古力娜扎"];
foreach ($myarray as $item => $value){
echo "key为{$item}的值是:{$value}<br>";
}
echo "第一个学生的姓名为:".$myarray[0];
$myarray = ["student1"=>"迪丽热巴","马尔扎哈","student3"=>"古力娜扎"]; foreach ($myarray as $item => $value){ echo "key为{$item}的值是:{$value}<br>"; } echo "第一个学生的姓名为:".$myarray[0];
$myarray = ["student1"=>"迪丽热巴","马尔扎哈","student3"=>"古力娜扎"];
foreach ($myarray as $item => $value){
    echo "key为{$item}的值是:{$value}<br>";
}
echo "第一个学生的姓名为:".$myarray[0];

输出如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
key为student1的值是:迪丽热巴
key为0的值是:马尔扎哈
key为student3的值是:古力娜扎
第一个学生的姓名为:马尔扎哈
key为student1的值是:迪丽热巴 key为0的值是:马尔扎哈 key为student3的值是:古力娜扎 第一个学生的姓名为:马尔扎哈
key为student1的值是:迪丽热巴
key为0的值是:马尔扎哈
key为student3的值是:古力娜扎
第一个学生的姓名为:马尔扎哈

 

>> 阅读全文  >>

腾讯行为验证码API的PHP接入教程

By heiry on 2019-04-20 [ in 技术 ]

腾讯行为验证码QQcaptcha提供免费版的API(支持不大于2000次/小时的请求),依靠腾讯强大的云计算平台和大数据处理能力,QQcaptcha稳定性、可靠性属上乘,是中小应用安全验证的不错选择(介绍详见:http://www.mosang.net/575.html)。

接入也不复杂,以下为接入教程(PHP版):

1.  打开链接 https://007.qq.com/captcha/ 登录申请。

2. 绑定域名,新建验证码。可以需要选择应用场景(登录验证、秒杀、抽奖等)

3.成功后即可获得APP ID及App Secret Key。

4. 客户端接入:

a.引入JavaScript文件,在<head>区域引入JavaScript脚本:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<script src="https://ssl.captcha.qq.com/TCaptcha.js"></script>
<script src="https://ssl.captcha.qq.com/TCaptcha.js"></script>
<script src="https://ssl.captcha.qq.com/TCaptcha.js"></script>

b. 创建激活DOM对象(通过ID指定,默认为click事件触发)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<!--点击此元素会自动激活验证码-->
<!--id : 元素的id(必须)-->
<!--data-appid : AppID(必须)-->
<!--data-cbfn : 回调函数名(必须)-->
<!--data-biz-state : 业务自定义透传参数(可选)-->
<button id="TencentCaptcha"
data-appid="8888888" <!--这里"8888888"换成你自己的APP ID-->
data-cbfn="callback"
>点击认证</button>
<!--点击此元素会自动激活验证码--> <!--id : 元素的id(必须)--> <!--data-appid : AppID(必须)--> <!--data-cbfn : 回调函数名(必须)--> <!--data-biz-state : 业务自定义透传参数(可选)--> <button id="TencentCaptcha" data-appid="8888888" <!--这里"8888888"换成你自己的APP ID--> data-cbfn="callback" >点击认证</button>
<!--点击此元素会自动激活验证码-->
<!--id : 元素的id(必须)-->
<!--data-appid : AppID(必须)-->
<!--data-cbfn : 回调函数名(必须)-->
<!--data-biz-state : 业务自定义透传参数(可选)-->
<button id="TencentCaptcha"
        data-appid="8888888" <!--这里"8888888"换成你自己的APP ID-->
        data-cbfn="callback"
>点击认证</button>

c.为验证码创建回调函数(函数名与上一步data-cbfn指定的相同)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
window.callback = function(res){
console.log(res)
// res(用户主动关闭验证码)= {ret: 2, ticket: null}
// res(验证成功) = {ret: 0, ticket: "String", randstr: "String"}
if(res.ret === 0){
alert(res.ticket) // 票据
}
}
window.callback = function(res){ console.log(res) // res(用户主动关闭验证码)= {ret: 2, ticket: null} // res(验证成功) = {ret: 0, ticket: "String", randstr: "String"} if(res.ret === 0){ alert(res.ticket) // 票据 } }
window.callback = function(res){
    console.log(res)

    // res(用户主动关闭验证码)= {ret: 2, ticket: null}
    // res(验证成功) = {ret: 0, ticket: "String", randstr: "String"}
    if(res.ret === 0){
        alert(res.ticket)   // 票据
    }
}

上面是官方给出的示例,实际应用代码参考如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
window.callback = function(res){
if(res.ret === 0){
$.post("http://www.mosang.net/isallowlogin.php",//异步发送ticket和randstr到服务端
{
ticket:res.ticket,
randstr:res.randstr
},
function(data,status){
if(data.allowLogin == "yes"){
alert("防恶意行为认证成功");
}
else
{
alert("防恶意行为认证失败");
};
});
}
}
window.callback = function(res){ if(res.ret === 0){ $.post("http://www.mosang.net/isallowlogin.php",//异步发送ticket和randstr到服务端 { ticket:res.ticket, randstr:res.randstr }, function(data,status){ if(data.allowLogin == "yes"){ alert("防恶意行为认证成功"); } else { alert("防恶意行为认证失败"); }; }); } }
window.callback = function(res){
    if(res.ret === 0){		
    $.post("http://www.mosang.net/isallowlogin.php",//异步发送ticket和randstr到服务端
      {
      ticket:res.ticket,
      randstr:res.randstr
      },
      function(data,status){
      if(data.allowLogin == "yes"){
        alert("防恶意行为认证成功");
      }
      else
      {
        alert("防恶意行为认证失败");
      };
      });
    }
}

5. 服务器端验证程序isallowlogin.php,向腾讯服务器发送GET请求,具体参数参照官方给出列表:

isallowlogin.php请求及返回数据参考如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
$ip = $_SERVER['REMOTE_ADDR'];
$ticket = $_POST["ticket"];
$randstr = $_POST["randstr"];
$tagetUrl='https://ssl.captcha.qq.com/ticket/verify?aid=888888&AppSecretKey=0wLlYnHsmrfrfrfr&Ticket='.$ticket.'&Randstr='.$randstr.'&UserIP='.$ip;
//这里aid参数换成你自己的APPID值 ,AppSecretKey参数换成你自己的AppSecretKey值。
$resData = file_get_contents($tagetUrl);//向腾讯服务器发起GET请求
header('Content-type:text/json;charset=utf-8');
$info = json_decode(trim($resData,chr(239).chr(187).chr(191)),true);//去掉BOM头的不可见字符,并转化为数组
if($info["response"] == 1){
session_start();
$_SESSION['Login'] = "yes";
echo('{"allowLogin":"yes"}');
}
else
{
echo('{"allowLogin":"no"}');
}
?>
<?php $ip = $_SERVER['REMOTE_ADDR']; $ticket = $_POST["ticket"]; $randstr = $_POST["randstr"]; $tagetUrl='https://ssl.captcha.qq.com/ticket/verify?aid=888888&AppSecretKey=0wLlYnHsmrfrfrfr&Ticket='.$ticket.'&Randstr='.$randstr.'&UserIP='.$ip; //这里aid参数换成你自己的APPID值 ,AppSecretKey参数换成你自己的AppSecretKey值。 $resData = file_get_contents($tagetUrl);//向腾讯服务器发起GET请求 header('Content-type:text/json;charset=utf-8'); $info = json_decode(trim($resData,chr(239).chr(187).chr(191)),true);//去掉BOM头的不可见字符,并转化为数组 if($info["response"] == 1){ session_start(); $_SESSION['Login'] = "yes"; echo('{"allowLogin":"yes"}'); } else { echo('{"allowLogin":"no"}'); } ?>
<?php
$ip = $_SERVER['REMOTE_ADDR'];
$ticket = $_POST["ticket"];
$randstr = $_POST["randstr"];
$tagetUrl='https://ssl.captcha.qq.com/ticket/verify?aid=888888&AppSecretKey=0wLlYnHsmrfrfrfr&Ticket='.$ticket.'&Randstr='.$randstr.'&UserIP='.$ip;
//这里aid参数换成你自己的APPID值 ,AppSecretKey参数换成你自己的AppSecretKey值。
$resData = file_get_contents($tagetUrl);//向腾讯服务器发起GET请求
header('Content-type:text/json;charset=utf-8');
$info = json_decode(trim($resData,chr(239).chr(187).chr(191)),true);//去掉BOM头的不可见字符,并转化为数组
if($info["response"] == 1){
  session_start();
  $_SESSION['Login'] = "yes";
  echo('{"allowLogin":"yes"}');
}
else
{
  echo('{"allowLogin":"no"}');
}
?>

至此,接入完成,是不是很简单?

>> 阅读全文  >>

Thread继承和Runnable接口创建多线程比较

By heiry on 2019-04-20 [ in 技术 ]

java中创建多线程主要是三种方式,1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法 3.实现Callable接口,重写call方法。最常用的是前两种,很多书上都提到2方式上的优势,理由是方便实现资源共享,代码和数据的分离,更好体现面向对象思想。实际上,我认为这两种没有太大区别,通过线程同步两者基本没什么差别,看个人习惯而已。

继承方式创建多线程:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class ThreadDemo{
public static void main(String [] args){
new NewThread().start();
while(true){
System.out.println("main thread is running");
}
}
}
class NewThread extends Thread{
public void run(){
while(true){
System.out.println(Thread.currentThread().getName()+"is running");
}
}
}
public class ThreadDemo{ public static void main(String [] args){ new NewThread().start(); while(true){ System.out.println("main thread is running"); } } } class NewThread extends Thread{ public void run(){ while(true){ System.out.println(Thread.currentThread().getName()+"is running"); } } }
public class ThreadDemo{
public static void main(String [] args){
new NewThread().start();
while(true){
System.out.println("main thread is running");
}
}
}
class NewThread extends Thread{
public void run(){ 
while(true){
System.out.println(Thread.currentThread().getName()+"is running");
}
}
}

Thread(Runnable target)是Thread类的构造方法,Runnable参数为接口类;

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class ThreadMain{
public static void main(String [] args){
ThreadRunable runableDemo = new ThreadRunable();
Thread newThread = new Thread(runableDemo);
newThread.start();
while(true){
System.out.println("main thread is running");
}
}
}
class ThreadRunable implements Runnable{
public void run(){
while(true){
System.out.println(Thread.currentThread().getName()+"is running");
}
}
}
public class ThreadMain{ public static void main(String [] args){ ThreadRunable runableDemo = new ThreadRunable(); Thread newThread = new Thread(runableDemo); newThread.start(); while(true){ System.out.println("main thread is running"); } } } class ThreadRunable implements Runnable{ public void run(){ while(true){ System.out.println(Thread.currentThread().getName()+"is running"); } } }
public class ThreadMain{
    public static void main(String [] args){
        ThreadRunable runableDemo = new ThreadRunable();
        Thread newThread = new Thread(runableDemo);
        newThread.start();
        while(true){
            System.out.println("main thread is running");
}
}
}
class ThreadRunable implements Runnable{
    public void run(){
        while(true){
            System.out.println(Thread.currentThread().getName()+"is running");
}
}
}

 

 

>> 阅读全文  >>

静态代码块的加载与执行

By heiry on 2019-04-17 [ in 技术 ]

java中的静态代码块,在被载入内存的时候被执行,而且只执行一次,正因如此,某些场景下我们可以用静态代码块实现单例模式。但是对于静态代码块的执行顺序,如果没好好理解,就容易掉坑。

静态代码块装载时才执行。类在第一次被使用的时候才被装载,而不是程序启动时就装载所有的类,因此含静态代码块的所在类被装载时静态代码块才会运行。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class StaticCodeTest {
public static void main(String [] args){
System.out.println("main fun running");
}
static {
System.out.println("this static area run auto");
}
}
public class StaticCodeTest { public static void main(String [] args){ System.out.println("main fun running"); } static { System.out.println("this static area run auto"); } }
public class StaticCodeTest { 
        public static void main(String [] args){ 
        System.out.println("main fun running");
    }
  static { 
        System.out.println("this static area run auto"); 
    } 
}

以上代码运行结果如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
this static area run auto
main fun running
this static area run auto main fun running
this static area run auto
main fun running

StaticCodeTest类在载入时自动运行了静态代码块,而且静态代码块优先于main方法执行。

在上述的代码基础上,我们加入两个类

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class StaticCodeTest {
public static void main(String [] args){
System.out.println("main fun running");
}
static {
System.out.println("this static area run auto");
}
}
class StaticAreaDemo_1{
static String siteName = "blog.mosang.net";
static{
System.out.println("来自"+siteName+"的静态代码块1被执行");
}
}
class StaticAreaDemo_2{
static String siteName = "www.mosang.net";
static{ System.out.println("来自"+siteName+"的静态代码块1被执行");
}
}
public class StaticCodeTest { public static void main(String [] args){ System.out.println("main fun running"); } static { System.out.println("this static area run auto"); } } class StaticAreaDemo_1{ static String siteName = "blog.mosang.net"; static{ System.out.println("来自"+siteName+"的静态代码块1被执行"); } } class StaticAreaDemo_2{ static String siteName = "www.mosang.net"; static{ System.out.println("来自"+siteName+"的静态代码块1被执行"); } }
public class StaticCodeTest { 
    
        public static void main(String [] args){ 
        System.out.println("main fun running");
      
    }
  static { 
        System.out.println("this static area run auto"); 
    } 
}

class StaticAreaDemo_1{
static String siteName = "blog.mosang.net";
static{
System.out.println("来自"+siteName+"的静态代码块1被执行");
}
}
class StaticAreaDemo_2{
static String siteName = "www.mosang.net";
static{ System.out.println("来自"+siteName+"的静态代码块1被执行");
}
}

运行结果如下

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
this static area run auto
main fun running
this static area run auto main fun running
this static area run auto
main fun running

可见,如果静态代码块所在类没有被装载,静态代码块是不会自动运行的。

创建新增两个类的对象,代码及运行结果如下

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class StaticCodeTest {
public static void main(String [] args){
System.out.println("main fun running");
StaticAreaDemo_1 p1 = new StaticAreaDemo_1();
StaticAreaDemo_2 p2 = new StaticAreaDemo_2();
}
static {
System.out.println("this static area run auto");
}
}
class StaticAreaDemo_1{
static String siteName = "blog.mosang.net";
static{
System.out.println("来自"+siteName+"的静态代码块被执行");
}
}
class StaticAreaDemo_2{
static String siteName = "www.mosang.net";
static{ System.out.println("来自"+siteName+"的静态代码块被执行");
}
}
public class StaticCodeTest { public static void main(String [] args){ System.out.println("main fun running"); StaticAreaDemo_1 p1 = new StaticAreaDemo_1(); StaticAreaDemo_2 p2 = new StaticAreaDemo_2(); } static { System.out.println("this static area run auto"); } } class StaticAreaDemo_1{ static String siteName = "blog.mosang.net"; static{ System.out.println("来自"+siteName+"的静态代码块被执行"); } } class StaticAreaDemo_2{ static String siteName = "www.mosang.net"; static{ System.out.println("来自"+siteName+"的静态代码块被执行"); } }
public class StaticCodeTest { 
    
        public static void main(String [] args){ 
        System.out.println("main fun running");
      StaticAreaDemo_1 p1 = new StaticAreaDemo_1();
    StaticAreaDemo_2 p2 = new StaticAreaDemo_2();
      
    }
  static { 
        System.out.println("this static area run auto"); 
    } 
}

class StaticAreaDemo_1{
static String siteName = "blog.mosang.net";
static{
System.out.println("来自"+siteName+"的静态代码块被执行");
}
}
class StaticAreaDemo_2{
static String siteName = "www.mosang.net";
static{ System.out.println("来自"+siteName+"的静态代码块被执行");
}
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
this static area run auto
main fun running
来自blog.mosang.net的静态代码块被执行
来自www.mosang.net的静态代码块被执行
this static area run auto main fun running 来自blog.mosang.net的静态代码块被执行 来自www.mosang.net的静态代码块被执行
this static area run auto
main fun running
来自blog.mosang.net的静态代码块被执行
来自www.mosang.net的静态代码块被执行

以上可看出,装载StaticAreaDemo_1和StaticAreaDemo_2,其中的代码块执行,但是并没有优先于main方法执行。

上述代码更改为同一个类创建两个对象:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class StaticCodeTest {
public static void main(String [] args){
System.out.println("main fun running");
StaticAreaDemo_1 p1 = new StaticAreaDemo_1();
StaticAreaDemo_1 p2 = new StaticAreaDemo_1();
}
static {
System.out.println("this static area run auto");
}
}
class StaticAreaDemo_1{
static String siteName = "blog.mosang.net";
static{
System.out.println("来自"+siteName+"的静态代码块被执行");
}
}
class StaticAreaDemo_2{
static String siteName = "www.mosang.net";
static{ System.out.println("来自"+siteName+"的静态代码块被执行");
}
}
public class StaticCodeTest { public static void main(String [] args){ System.out.println("main fun running"); StaticAreaDemo_1 p1 = new StaticAreaDemo_1(); StaticAreaDemo_1 p2 = new StaticAreaDemo_1(); } static { System.out.println("this static area run auto"); } } class StaticAreaDemo_1{ static String siteName = "blog.mosang.net"; static{ System.out.println("来自"+siteName+"的静态代码块被执行"); } } class StaticAreaDemo_2{ static String siteName = "www.mosang.net"; static{ System.out.println("来自"+siteName+"的静态代码块被执行"); } }
public class StaticCodeTest { 
    
        public static void main(String [] args){ 
        System.out.println("main fun running");
      StaticAreaDemo_1 p1 = new StaticAreaDemo_1();
    StaticAreaDemo_1 p2 = new StaticAreaDemo_1();
      
    }
  static { 
        System.out.println("this static area run auto"); 
    } 
}

class StaticAreaDemo_1{
static String siteName = "blog.mosang.net";
static{
System.out.println("来自"+siteName+"的静态代码块被执行");
}
}
class StaticAreaDemo_2{
static String siteName = "www.mosang.net";
static{ System.out.println("来自"+siteName+"的静态代码块被执行");
}
}

运行结果:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
this static area run auto
main fun running
来自blog.mosang.net的静态代码块被执行
this static area run auto main fun running 来自blog.mosang.net的静态代码块被执行
this static area run auto
main fun running
来自blog.mosang.net的静态代码块被执行

可见,尽管创建了两个对象,静态代码块只执行了一次。

>> 阅读全文  >>

委托在异步模式下的运用

By heiry on 2019-04-14 [ in 技术 ]

异步模式下,获得数据的时间点通常具有不确定性,在封装异步方法时,通常要用到委托来达到返回数据和操作数据的目的。

异步请求中委托一般通过高阶函数来实现(函数作为参数传递或函数作为返回值返回)。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
var mytest = function(vars){
console.log(vars+"作为参数传入");
}
function showDemo(foo) {
foo("demo:");
}
showDemo(mytest);
var mytest = function(vars){ console.log(vars+"作为参数传入"); } function showDemo(foo) { foo("demo:"); } showDemo(mytest);
var mytest = function(vars){
    console.log(vars+"作为参数传入");
}
function showDemo(foo) {
foo("demo:");
}

showDemo(mytest);

通过委托实现异步请求方法的封装:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
var getInfo = function(url,articleId,callBack){
$.ajax(url+"?id="+articleId,function(data){
if(typeof callBack == "function"){
callBack(data);
}
});
}
getInfo("https://blog.mosang.net",2856,function(data){console.log(data)});
var getInfo = function(url,articleId,callBack){ $.ajax(url+"?id="+articleId,function(data){ if(typeof callBack == "function"){ callBack(data); } }); } getInfo("https://blog.mosang.net",2856,function(data){console.log(data)});
var getInfo = function(url,articleId,callBack){
    $.ajax(url+"?id="+articleId,function(data){
        if(typeof callBack == "function"){
            callBack(data);
        }
    });
}
getInfo("https://blog.mosang.net",2856,function(data){console.log(data)});

 

 

 

>> 阅读全文  >>

Java中包(Package)的深入理解

By heiry on 2019-04-12 [ in 技术 ]

被一个java新人请教关于包的理解和使用,想起了自己当年刚学java时候的体会。

包-Pakage,概念理解和使用不难,但对于刚接触java的人而言,有点抽象和不解。

人人皆知,java中的包主要用于解决类的重名问题,类似于XML、C#,PHP等命名空间的概念,但与这些语言有所区别,它既有命名空间的逻辑分割又有物理上的实际目录划分。

一.使用

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pakage mosang.tech //表明A.java 源文件中,所有类都位于mosang.tech包中
public class A{
public static void main(String [] args){
new B().showInfo();
}
}
class B{
public showInfo(){
System.out.print("this a method of how to using pakage");
}
}
pakage mosang.tech //表明A.java 源文件中,所有类都位于mosang.tech包中 public class A{ public static void main(String [] args){ new B().showInfo(); } } class B{ public showInfo(){ System.out.print("this a method of how to using pakage"); } }
pakage mosang.tech //表明A.java 源文件中,所有类都位于mosang.tech包中
public class A{
public static void main(String [] args){
new B().showInfo();
}
}
class B{
public showInfo(){
System.out.print("this a method of how to using pakage");
}
}

假设我们已经将classpath设置为A.java所在的目录:

上述代码运行编译后会自动生成mosang/tech文件夹,同时得到一个B.class字节码文件位于tech文件夹中

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
javac -d . A.java
javac -d . A.java
javac -d . A.java

这时候,运行B.class文件需要带完整包名,哪怕我们在命令行窗口进入了mosang/tech目录。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
java mosang.tech.B
java mosang.tech.B
java mosang.tech.B

这就是包的基本用法。

二.陷阱一:类名的使用

如果我们在命令行进入mosang/tech目录运行B.class,编译器会提示找不到文件,因为类的名字已是mosang.tech.B而不是B。

二.陷阱二:classpath路径与包名

JVM在加载带包名的路径时候,会先到classpath指定的目录,再从此按照包名结构去查找class文件。如果我们在命令行进入mosang/tech目录运行mosang.tech.B,同样会报错,因为此时的完整路径变成了classpath/mosang/tech/mosang/tech/B.class

三.陷阱三:包名与目录名

java中,包名必须经过程序中pakage语句来指定,而不是靠目录结构来指定的,是先有了包名,才需要相应的目录结构。我们来做个试验:

删除原生成的B.lass文件,在源代码A.java中,将pakage语句注释掉,重新编译得到B.class,将B.class拷贝到mosang/tech文件夹中,classpath目录下运行mosang.tech.B,会出错,因为此时的类名是B而不是mosang.tech.B。

所以,我们常常误以为把一个类文件放到了一个目录中,这个目录结构就自然成了包名,这就大错特错了。这点很多人包含有多年java经验的人都会犯错,绝大部分新手更是有这种自以为是理解。

 

 

 

>> 阅读全文  >>

AJAX跨域与URI大小写问题

By heiry on 2019-03-27 [ in 技术 ]

以前解决过很多异步请求跨域的问题,自认为不会有什么难点,可今天调试一个项目API的时候遇到了之前没遇到的问题,弄了好久才解决,记录如下:

项目中涉及一个主域(以www.abc.com表示),子域(以s.abc.com表示),子域控制器s.abc.com/Action向主域www.abc.com/Reply发异步POST请求,www.abc.com/Reply发出Header参数“Access-Control-Allow-Origin:http://s.abc.com““Access-Control-Allow-Methods:POST”,按理说这应该没什么问题了,但问题来了:
1. 直接访问通过URL:www.abc.com/Reply访问,可以看到添加的“Access-Control-Allow-Origin“等响应头,也能正常传递JSON,如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: http://s.abc.com
Access-Control-Expose-Headers: Authorization
Content-Encoding: gzip
Content-Length: 138
Content-Type: text/json; charset=utf-8
Date: Wed, 27 Mar 2019 07:03:09 GMT
Server: Tengine
Vary: Accept-Encoding
Access-Control-Allow-Methods: POST Access-Control-Allow-Origin: http://s.abc.com Access-Control-Expose-Headers: Authorization Content-Encoding: gzip Content-Length: 138 Content-Type: text/json; charset=utf-8 Date: Wed, 27 Mar 2019 07:03:09 GMT Server: Tengine Vary: Accept-Encoding
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: http://s.abc.com
Access-Control-Expose-Headers: Authorization
Content-Encoding: gzip
Content-Length: 138
Content-Type: text/json; charset=utf-8
Date: Wed, 27 Mar 2019 07:03:09 GMT
Server: Tengine
Vary: Accept-Encoding

2. 但通过子域的AJAX请求,死活就得不到添加的Headers参数,FF及Chrome均提示提示同源错误“原因:头缺少 ‘Access-Control-Allow-Origin’”,明明已经设置,就是没有传递,而之前做的一个接口几乎代码一样,但却能正常返回值,确实让人百思不得其解。
无奈之下,只能检查服务器设置,发现URLrewrite有如下规则:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<rule name="LowerCaseRule1" stopProcessing="true">
<match url="[A-Z]" ignoreCase="false" />
<action type="Redirect" url="{ToLower:{URL}}" />
</rule>
<rule name="LowerCaseRule1" stopProcessing="true"> <match url="[A-Z]" ignoreCase="false" /> <action type="Redirect" url="{ToLower:{URL}}" /> </rule>
<rule name="LowerCaseRule1" stopProcessing="true">
                    <match url="[A-Z]" ignoreCase="false" />
                    <action type="Redirect" url="{ToLower:{URL}}" />
</rule>

 

恍然大悟!

这个是SEO常设规则,用来规避因为URL大小写而带来搜索引擎识别为不同站点的问题,而项目很多CLASS命名都根据大小驼峰规则,Controls也是大小混写,这条重写规则强制将文件名小写返回,而AJAX请求则认为是两个不同请求,导致Headers参数无法正常接收。

取消此规则,问题解决。

>> 阅读全文  >>


© 2009-2024 MOSANG.NET DESIGNED BY HEIRY