Collection <KProperty1 <I,* >>如何获取属性实例

时间:2019-08-13 11:28:33

标签: kotlin

我目前正在使用Reflection使用class.memberProperties函数在运行时检查元素。 properties的类型为collection<KProperty1<I, *>>,因此我遍历每个KProperty对象,通过检查名称是否等于“ nameIWant”来找到所需的对象,尽管我会而是能够通过在KProperty上使用.get()方法从property获取属性的实例,这样我就可以进行如下检查:

if (property.get(receiver) is ClassIWant) {
  //Do something
}

我的代码如下:

val properties = request.payload::class.memberProperties
  properties.forEach { property ->
    run {
      if (property.name.equals("nameIWant")) {

      }
    }
  }

到目前为止,我一直在尝试对.get()类型使用KProperty1方法,但是它接受类型为receiver的参数Nothing。我无法计算出要调用.get()方法并获取属性的特定实例所需要传递的内容。我还检查了以下文档:https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-property1/index.html,但实际上并没有帮助。

2 个答案:

答案 0 :(得分:0)

您可以为package altis.trackingapp.track; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback { private GoogleMap mMap; String latitude=""; String longitude=""; String imei; private static String url; String status; Double myLat=0.0; Double myLng=0.0; private String TAG = MapsActivity.class.getSimpleName(); private ProgressDialog pDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); latitude=getIntent().getStringExtra("latitude"); longitude=getIntent().getStringExtra("longitude"); imei=getIntent().getStringExtra("imei"); url = "http://139.162.37.96/track/api2/geteventstatus.php?imei="+imei; // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); new GetEventStatus().execute(); } /** * Manipulates the map once available. * This callback is triggered when the map is ready to be used. * This is where we can add markers or lines, add listeners or move the camera. In this case, * we just add a marker near Sydney, Australia. * If Google Play services is not installed on the device, the user will be prompted to install * it inside the SupportMapFragment. This method will only be triggered once the user has * installed Google Play services and returned to the app. */ @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; myLat = Double.parseDouble(latitude); myLng = Double.parseDouble(longitude); Toast.makeText(MapsActivity.this, "Lat:"+myLat+"\tLng:"+myLng, Toast.LENGTH_LONG).show(); if (myLat==0 && myLng==0) { Toast.makeText(MapsActivity.this,"Invalid Location",Toast.LENGTH_SHORT).show(); Intent dev = new Intent(MapsActivity.this,DevicesNavActivity.class); startActivity(dev); } else if (myLat==null && myLng==null) { Toast.makeText(MapsActivity.this,"No Data Found",Toast.LENGTH_SHORT).show(); Intent dev = new Intent(MapsActivity.this,DevicesNavActivity.class); startActivity(dev); } else { LatLng location = new LatLng(myLat, myLng); //Adding Marker to Location MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(location) .title("Marker") .snippet("My Marker") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)); //Displaying the Info Window InfoWindowData info = new InfoWindowData(); info.setName("Co-Ordinates of "+imei); info.setLatitude(latitude); info.setLongitude(longitude); CustomInfoWindowActivity customInfoWindow = new CustomInfoWindowActivity(this); mMap.setInfoWindowAdapter(customInfoWindow); Marker m = mMap.addMarker(markerOptions); m.setTag(info); m.showInfoWindow(); // Add a marker in Location and move the camera // mMap.addMarker(new MarkerOptions().position(location).title("Marker")); //mMap.moveCamera(CameraUpdateFactory.newLatLng(location)); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 17f)); mMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() { @Override public void onInfoWindowClick(Marker marker) { Intent event = new Intent(MapsActivity.this, EventGenerateActivity.class); event.putExtra("latitude",latitude); event.putExtra("longitude",longitude); event.putExtra("imei",imei); event.putExtra("status",status); startActivity(event); } }); } } /** * Async task class to get json by making HTTP call */ private class GetEventStatus extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... arg0) { HttpHandler sh = new HttpHandler(); // Making a request to url and getting response String jsonStr = sh.makeServiceCall(url); Log.e(TAG, "Response from url: " + jsonStr); if (jsonStr.trim().equals("1")) status = "1"; else status = "0"; Log.e(TAG, "Status: " +status); return null; } } public void onBackPressed() { Intent dev = new Intent(MapsActivity.this,DevicesNavActivity.class); startActivity(dev); return; } } 创建一个KType,然后检查属性的ClassIWant。会是这样的:

returnType

您可以将属性变量转换为正确的类型并使用val properties = request.payload::class.memberProperties val desiredType = ClassIWant::class.createType() properties.forEach { property -> if (property.name == "nameIWant" && property.returnType == desiredType) { //todo } }

get

答案 1 :(得分:0)

如果要获取属性的值,请将类转换为不变类型。

instance::class.memberProperties.first() // returns KProperty1<out Instance, *>
(instance::class as KClass<Instance>).memberProperties.first() // returns KProperty1<Instance, *>

如果您的KClass<Instance>KClass<*>,请使用Any作为Instance

为什么KProperty.call接受Nothing作为接收者? 因为instance::class返回KClass<out Instance>,它将协变类型参数传播到属性,属性变成KProperty<out Instance, *>,这将可能的方法接收者缩小为Instance的任何子类型,但是因为不知道哪个,我们不能安全地提供Instance的任何实例,如方差规则所示,此处将通用类型参数限制为Nothing,这意味着根本无法调用该方法。

为什么::class设计为协变的? 为了保证安全。这似乎是不合逻辑的,因此一直是大辩论的问题。

如果您想知道该属性可以返回的值的类型,请使用

property.returnType

它返回一个KType,它是Kotlin的Java Type的版本,它是Class(它是Type的一种实现)的更通用的概念。

如果需要将KType“转换”为KClass,则需要执行与将Type转换为Class相同的操作,即获取该类型的原始类型。原始类型是去除所有常规信息的类型,是的,是已擦除类型。完成此操作的方法(似乎)更加复杂(涉及处理每个可能的KType / Type实现),我建议单独检查此问题的答案。

您将能够使用以下方法重用Java实现(您一定会自己找到):

kType.javaType.covertJavaTypeToJavaClass().kotlin  // returns KClass<*>

您的问题中的更正。如果您希望获得正确的答案,建议使用适当的术语: *您问题中的I是方法接收者的类型,而不是属性的值 * collection不是类型,Collection is * property is ClassIWant不明确,因为property.type是属性中值的类型,而property::class只是属性实现,is也是instanceof的检查,但是相应地,您需要使用KClass.isSubclassOf或Java中称为type.isAssignableFrom的内容(观察通话顺序),然​​后将您的条件设为ClassIWant.isSuperclassOf(property.type.getRawType()) * instance of the property属性具有值,而不是实例。只有类具有实例。实例是值,值是(某类的)实例,但是您仍然必须说instance representing the value of the property